Update clang to 97654.

This commit is contained in:
Roman Divacky 2010-03-03 17:28:16 +00:00
parent ecb7e5c8af
commit 79ade4e028
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=204643
371 changed files with 15460 additions and 4601 deletions

View File

@ -420,7 +420,7 @@
1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = "<group>"; tabWidth = 2; };
1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; };
1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; };
1A97825A1108BA18002B98FC /* CGVTT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTT.cpp; path = lib/CodeGen/CGVTT.cpp; sourceTree = "<group>"; };
1A97825A1108BA18002B98FC /* CGVTT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTT.cpp; path = lib/CodeGen/CGVTT.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDeclCXX.cpp; path = lib/CodeGen/CGDeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayoutBuilder.h; path = lib/AST/RecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; };

View File

@ -1,3 +1,4 @@
add_subdirectory(clang-interpreter)
add_subdirectory(PrintFunctionNames)
add_subdirectory(wpa)

View File

@ -9,6 +9,6 @@
LEVEL = ../../..
PARALLEL_DIRS := PrintFunctionNames wpa
PARALLEL_DIRS := clang-interpreter PrintFunctionNames wpa
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,30 @@
set(LLVM_NO_RTTI 1)
set(LLVM_USED_LIBS
clangFrontend
clangDriver
clangCodeGen
clangSema
clangChecker
clangAnalysis
clangRewrite
clangAST
clangParse
clangLex
clangBasic
)
set(LLVM_LINK_COMPONENTS
jit
interpreter
nativecodegen
bitreader
bitwriter
ipo
selectiondag
)
add_clang_executable(clang-interpreter
main.cpp
)
add_dependencies(clang-interpreter clang-headers)

View File

@ -0,0 +1,30 @@
##===- examples/clang-interpreter/Makefile -----------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
TOOLNAME = clang-interpreter
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
NO_INSTALL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
# Include this here so we can get the configuration of the targets that have
# been configured for construction. We have to do this early so we can set up
# LINK_COMPONENTS before including Makefile.rules
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
selectiondag
USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangSema.a \
clangChecker.a clangAnalysis.a clangRewrite.a clangAST.a \
clangParse.a clangLex.a clangBasic.a
include $(LLVM_SRC_ROOT)/Makefile.rules

View File

@ -0,0 +1,17 @@
This is an example of Clang based interpreter, for executing standalone C
programs.
It demonstrates the following features:
1. Parsing standard compiler command line arguments using the Driver library.
2. Constructing a Clang compiler instance, using the appropriate arguments
derived in step #1.
3. Invoking the Clang compiler to lex, parse, syntax check, and then generate
LLVM code.
4. Use the LLVM JIT functionality to execute the final module.
The implementation has many limitations and is not designed to be a full fledged
C interpreter. It is designed to demonstrate a simple but functional use of the
Clang compiler libraries.

View File

@ -0,0 +1,152 @@
//===-- examples/clang-interpreter/main.cpp - Clang C Interpreter Example -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CodeGenAction.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Config/config.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
#include "llvm/Target/TargetSelect.h"
using namespace clang;
using namespace clang::driver;
llvm::sys::Path GetExecutablePath(const char *Argv0) {
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
}
int Execute(llvm::Module *Mod, char * const *envp) {
llvm::InitializeNativeTarget();
std::string Error;
llvm::OwningPtr<llvm::ExecutionEngine> EE(
llvm::ExecutionEngine::createJIT(Mod, &Error));
if (!EE) {
llvm::errs() << "unable to make execution engine: " << Error << "\n";
return 255;
}
llvm::Function *EntryFn = Mod->getFunction("main");
if (!EntryFn) {
llvm::errs() << "'main' function not found in module.\n";
return 255;
}
// FIXME: Support passing arguments.
std::vector<std::string> Args;
Args.push_back(Mod->getModuleIdentifier());
return EE->runFunctionAsMain(EntryFn, Args, envp);
}
int main(int argc, const char **argv, char * const *envp) {
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
llvm::sys::Path Path = GetExecutablePath(argv[0]);
TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions());
Diagnostic Diags(&DiagClient);
Driver TheDriver(Path.getBasename(), Path.getDirname(),
llvm::sys::getHostTriple(),
"a.out", /*IsProduction=*/false, Diags);
TheDriver.setTitle("clang interpreter");
// FIXME: This is a hack to try to force the driver to do something we can
// recognize. We need to extend the driver library to support this use model
// (basically, exactly one input, and the operation mode is hard wired).
llvm::SmallVector<const char *, 16> Args(argv, argv + argc);
Args.push_back("-fsyntax-only");
llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args.size(),
Args.data()));
if (!C)
return 0;
// FIXME: This is copied from ASTUnit.cpp; simplify and eliminate.
// We expect to get back exactly one command job, if we didn't something
// failed. Extract that job from the compilation.
const driver::JobList &Jobs = C->getJobs();
if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
llvm::SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg);
C->PrintJob(OS, C->getJobs(), "; ", true);
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
return 1;
}
const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
Diags.Report(diag::err_fe_expected_clang_command);
return 1;
}
// Initialize a compiler invocation object from the clang (-cc1) arguments.
const driver::ArgStringList &CCArgs = Cmd->getArguments();
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
(const char**) CCArgs.data()+CCArgs.size(),
Diags);
// Show the invocation, with -v.
if (CI->getHeaderSearchOpts().Verbose) {
llvm::errs() << "clang invocation:\n";
C->PrintJob(llvm::errs(), C->getJobs(), "\n", true);
llvm::errs() << "\n";
}
// FIXME: This is copied from cc1_main.cpp; simplify and eliminate.
// Create a compiler instance to handle the actual work.
CompilerInstance Clang;
Clang.setLLVMContext(new llvm::LLVMContext);
Clang.setInvocation(CI.take());
// Create the compilers actual diagnostics engine.
Clang.createDiagnostics(int(CCArgs.size()), (char**) CCArgs.data());
if (!Clang.hasDiagnostics())
return 1;
// Infer the builtin include path if unspecified.
if (Clang.getHeaderSearchOpts().UseBuiltinIncludes &&
Clang.getHeaderSearchOpts().ResourceDir.empty())
Clang.getHeaderSearchOpts().ResourceDir =
CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
// Create and execute the frontend to generate an LLVM bitcode module.
llvm::OwningPtr<CodeGenAction> Act(new EmitLLVMOnlyAction());
if (!Clang.ExecuteAction(*Act))
return 1;
int Res = 255;
if (llvm::Module *Module = Act->takeModule())
Res = Execute(Module, envp);
// Shutdown.
llvm::llvm_shutdown();
return Res;
}

View File

@ -1,3 +1,12 @@
##===- examples/wpa/Makefile -------------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
TOOLNAME = clang-wpa
@ -7,6 +16,9 @@ NO_INSTALL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
# Include this here so we can get the configuration of the targets that have
# been configured for construction. We have to do this early so we can set up
# LINK_COMPONENTS before including Makefile.rules
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := bitreader mc core

View File

@ -18,6 +18,7 @@
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
@ -86,14 +87,12 @@ struct CXUnsavedFile {
const char *Filename;
/**
* \brief A null-terminated buffer containing the unsaved contents
* of this file.
* \brief A buffer containing the unsaved contents of this file.
*/
const char *Contents;
/**
* \brief The length of the unsaved contents of this buffer, not
* counting the NULL at the end of the buffer.
* \brief The length of the unsaved contents of this buffer.
*/
unsigned long Length;
};
@ -145,8 +144,8 @@ CINDEX_LINKAGE void clang_disposeString(CXString string);
*
* Here is an example:
*
* // excludeDeclsFromPCH = 1
* Idx = clang_createIndex(1);
* // excludeDeclsFromPCH = 1, displayDiagnostics=1
* Idx = clang_createIndex(1, 1);
*
* // IndexTest.pch was produced with the following command:
* // "clang -x c IndexTest.h -emit-ast -o IndexTest.pch"
@ -170,7 +169,8 @@ CINDEX_LINKAGE void clang_disposeString(CXString string);
* -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks
* (which gives the indexer the same performance benefit as the compiler).
*/
CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH);
CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
int displayDiagnostics);
/**
* \brief Destroy the given index.
@ -207,7 +207,7 @@ typedef void *CXFile;
/**
* \brief Retrieve the complete file and path name of the given file.
*/
CINDEX_LINKAGE const char *clang_getFileName(CXFile SFile);
CINDEX_LINKAGE CXString clang_getFileName(CXFile SFile);
/**
* \brief Retrieve the last modification time of the given file.
@ -387,28 +387,6 @@ enum CXDiagnosticSeverity {
CXDiagnostic_Fatal = 4
};
/**
* \brief Describes the kind of fix-it hint expressed within a
* diagnostic.
*/
enum CXFixItKind {
/**
* \brief A fix-it hint that inserts code at a particular position.
*/
CXFixIt_Insertion = 0,
/**
* \brief A fix-it hint that removes code within a range.
*/
CXFixIt_Removal = 1,
/**
* \brief A fix-it hint that replaces the code within a range with another
* string.
*/
CXFixIt_Replacement = 2
};
/**
* \brief A single diagnostic, containing the diagnostic's severity,
* location, text, source ranges, and fix-it hints.
@ -416,17 +394,99 @@ enum CXFixItKind {
typedef void *CXDiagnostic;
/**
* \brief Callback function invoked for each diagnostic emitted during
* translation.
*
* \param Diagnostic the diagnostic emitted during translation. This
* diagnostic pointer is only valid during the execution of the
* callback.
*
* \param ClientData the callback client data.
* \brief Determine the number of diagnostics produced for the given
* translation unit.
*/
CINDEX_LINKAGE unsigned clang_getNumDiagnostics(CXTranslationUnit Unit);
/**
* \brief Retrieve a diagnostic associated with the given translation unit.
*
* \param Unit the translation unit to query.
* \param Index the zero-based diagnostic number to retrieve.
*
* \returns the requested diagnostic. This diagnostic must be freed
* via a call to \c clang_disposeDiagnostic().
*/
CINDEX_LINKAGE CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit,
unsigned Index);
/**
* \brief Destroy a diagnostic.
*/
CINDEX_LINKAGE void clang_disposeDiagnostic(CXDiagnostic Diagnostic);
/**
* \brief Options to control the display of diagnostics.
*
* The values in this enum are meant to be combined to customize the
* behavior of \c clang_displayDiagnostic().
*/
enum CXDiagnosticDisplayOptions {
/**
* \brief Display the source-location information where the
* diagnostic was located.
*
* When set, diagnostics will be prefixed by the file, line, and
* (optionally) column to which the diagnostic refers. For example,
*
* \code
* test.c:28: warning: extra tokens at end of #endif directive
* \endcode
*
* This option corresponds to the clang flag \c -fshow-source-location.
*/
CXDiagnostic_DisplaySourceLocation = 0x01,
/**
* \brief If displaying the source-location information of the
* diagnostic, also include the column number.
*
* This option corresponds to the clang flag \c -fshow-column.
*/
CXDiagnostic_DisplayColumn = 0x02,
/**
* \brief If displaying the source-location information of the
* diagnostic, also include information about source ranges in a
* machine-parsable format.
*
* This option corresponds to the clang flag
* \c -fdiagnostics-print-source-range-info.
*/
CXDiagnostic_DisplaySourceRanges = 0x04
};
/**
* \brief Format the given diagnostic in a manner that is suitable for display.
*
* This routine will format the given diagnostic to a string, rendering
* the diagnostic according to the various options given. The
* \c clang_defaultDiagnosticDisplayOptions() function returns the set of
* options that most closely mimics the behavior of the clang compiler.
*
* \param Diagnostic The diagnostic to print.
*
* \param Options A set of options that control the diagnostic display,
* created by combining \c CXDiagnosticDisplayOptions values.
*
* \returns A new string containing for formatted diagnostic.
*/
CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic,
unsigned Options);
/**
* \brief Retrieve the set of display options most similar to the
* default behavior of the clang compiler.
*
* \returns A set of display options suitable for use with \c
* clang_displayDiagnostic().
*/
CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void);
/**
* \brief Print a diagnostic to the given file.
*/
typedef void (*CXDiagnosticCallback)(CXDiagnostic Diagnostic,
CXClientData ClientData);
/**
* \brief Determine the severity of the given diagnostic.
@ -476,69 +536,33 @@ CINDEX_LINKAGE CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic,
CINDEX_LINKAGE unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic);
/**
* \brief Retrieve the kind of the given fix-it.
* \brief Retrieve the replacement information for a given fix-it.
*
* \param Diagnostic the diagnostic whose fix-its are being queried.
* Fix-its are described in terms of a source range whose contents
* should be replaced by a string. This approach generalizes over
* three kinds of operations: removal of source code (the range covers
* the code to be removed and the replacement string is empty),
* replacement of source code (the range covers the code to be
* replaced and the replacement string provides the new code), and
* insertion (both the start and end of the range point at the
* insertion location, and the replacement string provides the text to
* insert).
*
* \param FixIt the zero-based index of the fix-it to query.
* \param Diagnostic The diagnostic whose fix-its are being queried.
*
* \param FixIt The zero-based index of the fix-it.
*
* \param ReplacementRange The source range whose contents will be
* replaced with the returned replacement string. Note that source
* ranges are half-open ranges [a, b), so the source code should be
* replaced from a and up to (but not including) b.
*
* \returns A string containing text that should be replace the source
* code indicated by the \c ReplacementRange.
*/
CINDEX_LINKAGE enum CXFixItKind
clang_getDiagnosticFixItKind(CXDiagnostic Diagnostic, unsigned FixIt);
/**
* \brief Retrieve the insertion information for an insertion fix-it.
*
* For a fix-it that describes an insertion into a text buffer,
* retrieve the source location where the text should be inserted and
* the text to be inserted.
*
* \param Diagnostic the diagnostic whose fix-its are being queried.
*
* \param FixIt the zero-based index of the insertion fix-it.
*
* \param Location will be set to the location where text should be
* inserted.
*
* \returns the text string to insert at the given location.
*/
CINDEX_LINKAGE CXString
clang_getDiagnosticFixItInsertion(CXDiagnostic Diagnostic, unsigned FixIt,
CXSourceLocation *Location);
/**
* \brief Retrieve the removal information for a removal fix-it.
*
* For a fix-it that describes a removal from a text buffer, retrieve
* the source range that should be removed.
*
* \param Diagnostic the diagnostic whose fix-its are being queried.
*
* \param FixIt the zero-based index of the removal fix-it.
*
* \returns a source range describing the text that should be removed
* from the buffer.
*/
CINDEX_LINKAGE CXSourceRange
clang_getDiagnosticFixItRemoval(CXDiagnostic Diagnostic, unsigned FixIt);
/**
* \brief Retrieve the replacement information for an replacement fix-it.
*
* For a fix-it that describes replacement of text in the text buffer
* with alternative text.
*
* \param Diagnostic the diagnostic whose fix-its are being queried.
*
* \param FixIt the zero-based index of the replacement fix-it.
*
* \param Range will be set to the source range whose text should be
* replaced with the returned text.
*
* \returns the text string to use as replacement text.
*/
CINDEX_LINKAGE CXString
clang_getDiagnosticFixItReplacement(CXDiagnostic Diagnostic, unsigned FixIt,
CXSourceRange *Range);
CINDEX_LINKAGE CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic,
unsigned FixIt,
CXSourceRange *ReplacementRange);
/**
* @}
@ -600,17 +624,13 @@ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile(
int num_clang_command_line_args,
const char **clang_command_line_args,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files,
CXDiagnosticCallback diag_callback,
CXClientData diag_client_data);
struct CXUnsavedFile *unsaved_files);
/**
* \brief Create a translation unit from an AST file (-emit-ast).
*/
CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex,
const char *ast_filename,
CXDiagnosticCallback diag_callback,
CXClientData diag_client_data);
const char *ast_filename);
/**
* \brief Destroy the specified CXTranslationUnit object.
@ -764,7 +784,19 @@ enum CXCursorKind {
* The translation unit cursor exists primarily to act as the root
* cursor for traversing the contents of a translation unit.
*/
CXCursor_TranslationUnit = 300
CXCursor_TranslationUnit = 300,
/* Attributes */
CXCursor_FirstAttr = 400,
/**
* \brief An attribute whose specific kind is not exposed via this
* interface.
*/
CXCursor_UnexposedAttr = 400,
CXCursor_IBActionAttr = 401,
CXCursor_IBOutletAttr = 402,
CXCursor_LastAttr = CXCursor_IBOutletAttr
};
/**
@ -856,6 +888,32 @@ CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind);
*/
CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind);
/**
* \brief Describe the linkage of the entity referred to by a cursor.
*/
enum CXLinkageKind {
/** \brief This value indicates that no linkage information is available
* for a provided CXCursor. */
CXLinkage_Invalid,
/**
* \brief This is the linkage for variables, parameters, and so on that
* have automatic storage. This covers normal (non-extern) local variables.
*/
CXLinkage_NoLinkage,
/** \brief This is the linkage for static variables and static functions. */
CXLinkage_Internal,
/** \brief This is the linkage for entities with external linkage that live
* in C++ anonymous namespaces.*/
CXLinkage_UniqueExternal,
/** \brief This is the linkage for entities with true, external linkage. */
CXLinkage_External
};
/**
* \brief Determine the linkage of the entity referred to be a given cursor.
*/
CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor);
/**
* @}
*/
@ -1221,7 +1279,7 @@ CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU,
*/
/* for debug/testing */
CINDEX_LINKAGE const char *clang_getCursorKindSpelling(enum CXCursorKind Kind);
CINDEX_LINKAGE CXString clang_getCursorKindSpelling(enum CXCursorKind Kind);
CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor,
const char **startBuf,
const char **endBuf,
@ -1229,7 +1287,7 @@ CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor,
unsigned *startColumn,
unsigned *endLine,
unsigned *endColumn);
CINDEX_LINKAGE void clang_enableStackTraces(void);
/**
* @}
*/
@ -1313,13 +1371,13 @@ enum CXCompletionChunkKind {
* - a Placeholder chunk for "int x"
* - an Optional chunk containing the remaining defaulted arguments, e.g.,
* - a Comma chunk for ","
* - a Placeholder chunk for "float x"
* - a Placeholder chunk for "float y"
* - an Optional chunk containing the last defaulted argument:
* - a Comma chunk for ","
* - a Placeholder chunk for "double z"
* - a RightParen chunk for ")"
*
* There are many ways two handle Optional chunks. Two simple approaches are:
* There are many ways to handle Optional chunks. Two simple approaches are:
* - Completely ignore optional chunks, in which case the template for the
* function "f" would only include the first parameter ("int x").
* - Fully expand all optional chunks, in which case the template for the
@ -1478,7 +1536,7 @@ clang_getCompletionChunkKind(CXCompletionString completion_string,
*
* \returns the text associated with the chunk at index \c chunk_number.
*/
CINDEX_LINKAGE const char *
CINDEX_LINKAGE CXString
clang_getCompletionChunkText(CXCompletionString completion_string,
unsigned chunk_number);
@ -1613,9 +1671,7 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
struct CXUnsavedFile *unsaved_files,
const char *complete_filename,
unsigned complete_line,
unsigned complete_column,
CXDiagnosticCallback diag_callback,
CXClientData diag_client_data);
unsigned complete_column);
/**
* \brief Free the given set of code-completion results.
@ -1623,6 +1679,26 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
CINDEX_LINKAGE
void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results);
/**
* \brief Determine the number of diagnostics produced prior to the
* location where code completion was performed.
*/
CINDEX_LINKAGE
unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *Results);
/**
* \brief Retrieve a diagnostic associated with the given code completion.
*
* \param Result the code completion results to query.
* \param Index the zero-based diagnostic number to retrieve.
*
* \returns the requested diagnostic. This diagnostic must be freed
* via a call to \c clang_disposeDiagnostic().
*/
CINDEX_LINKAGE
CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results,
unsigned Index);
/**
* @}
*/

View File

@ -67,6 +67,28 @@ namespace clang {
namespace Builtin { class Context; }
/// \brief A vector of C++ member functions that is optimized for
/// storing a single method.
class CXXMethodVector {
/// \brief Storage for the vector.
///
/// When the low bit is zero, this is a const CXXMethodDecl *. When the
/// low bit is one, this is a std::vector<const CXXMethodDecl *> *.
mutable uintptr_t Storage;
typedef std::vector<const CXXMethodDecl *> vector_type;
public:
CXXMethodVector() : Storage(0) { }
typedef const CXXMethodDecl **iterator;
iterator begin() const;
iterator end() const;
void push_back(const CXXMethodDecl *Method);
void Destroy();
};
/// ASTContext - This class holds long-lived AST nodes (such as types and
/// decls) that can be referred to throughout the semantic analysis of a file.
class ASTContext {
@ -219,6 +241,14 @@ class ASTContext {
llvm::DenseMap<FieldDecl *, FieldDecl *> InstantiatedFromUnnamedFieldDecl;
/// \brief Mapping that stores the methods overridden by a given C++
/// member function.
///
/// Since most C++ member functions aren't virtual and therefore
/// don't override anything, we store the overridden functions in
/// this map on the side rather than within the CXXMethodDecl structure.
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
TranslationUnitDecl *TUDecl;
/// SourceMgr - The associated SourceManager object.
@ -310,6 +340,19 @@ class ASTContext {
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
// Access to the set of methods overridden by the given C++ method.
typedef CXXMethodVector::iterator overridden_cxx_method_iterator;
overridden_cxx_method_iterator
overridden_methods_begin(const CXXMethodDecl *Method) const;
overridden_cxx_method_iterator
overridden_methods_end(const CXXMethodDecl *Method) const;
/// \brief Note that the given C++ \p Method overrides the given \p
/// Overridden method.
void addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden);
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
@ -529,11 +572,11 @@ class ASTContext {
/// list. isVariadic indicates whether the argument list includes '...'.
QualType getFunctionType(QualType ResultTy, const QualType *ArgArray,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec = false,
bool hasAnyExceptionSpec = false,
unsigned NumExs = 0, const QualType *ExArray = 0,
bool NoReturn = false,
CallingConv CallConv = CC_Default);
unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec,
unsigned NumExs, const QualType *ExArray,
bool NoReturn,
CallingConv CallConv);
/// getTypeDeclType - Return the unique reference to the type for
/// the specified type declaration.
@ -882,9 +925,8 @@ class ASTContext {
llvm::SmallVectorImpl<FieldDecl*> &Fields);
void ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars,
bool CollectSynthesized = true);
void CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
void CollectNonClassIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
void CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);

View File

@ -156,6 +156,12 @@ namespace clang {
/// \returns the equivalent identifier in the "to" context.
IdentifierInfo *Import(IdentifierInfo *FromId);
/// \brief Import the given Objective-C selector from the "from"
/// context into the "to" context.
///
/// \returns the equivalent selector in the "to" context.
Selector Import(Selector FromSel);
/// \brief Import the given file ID from the "from" context into the
/// "to" context.
///

View File

@ -62,7 +62,8 @@ class Attr {
FormatArg,
GNUInline,
Hiding,
IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with
IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro.
IBActionKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro.
Malloc,
NoDebug,
NoInline,
@ -72,8 +73,10 @@ class Attr {
ObjCException,
ObjCNSObject,
Override,
CFReturnsRetained, // Clang/Checker-specific.
NSReturnsRetained, // Clang/Checker-specific.
CFReturnsRetained, // Clang/Checker-specific.
CFReturnsNotRetained, // Clang/Checker-specific.
NSReturnsRetained, // Clang/Checker-specific.
NSReturnsNotRetained, // Clang/Checker-specific.
Overloadable, // Clang-specific
Packed,
PragmaPack,
@ -91,6 +94,7 @@ class Attr {
WarnUnusedResult,
Weak,
WeakImport,
WeakRef,
FIRST_TARGET_ATTRIBUTE,
DLLExport,
@ -300,19 +304,6 @@ class DestructorAttr : public Attr {
static bool classof(const DestructorAttr *A) { return true; }
};
class GNUInlineAttr : public Attr {
public:
GNUInlineAttr() : Attr(GNUInline) {}
virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
return A->getKind() == GNUInline;
}
static bool classof(const GNUInlineAttr *A) { return true; }
};
class IBOutletAttr : public Attr {
public:
IBOutletAttr() : Attr(IBOutletKind) {}
@ -326,11 +317,25 @@ class IBOutletAttr : public Attr {
static bool classof(const IBOutletAttr *A) { return true; }
};
DEF_SIMPLE_ATTR(Malloc);
DEF_SIMPLE_ATTR(NoReturn);
class IBActionAttr : public Attr {
public:
IBActionAttr() : Attr(IBActionKind) {}
virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
return A->getKind() == IBActionKind;
}
static bool classof(const IBActionAttr *A) { return true; }
};
DEF_SIMPLE_ATTR(AnalyzerNoReturn);
DEF_SIMPLE_ATTR(Deprecated);
DEF_SIMPLE_ATTR(Final);
DEF_SIMPLE_ATTR(GNUInline);
DEF_SIMPLE_ATTR(Malloc);
DEF_SIMPLE_ATTR(NoReturn);
class SectionAttr : public AttrWithString {
public:
@ -353,6 +358,7 @@ DEF_SIMPLE_ATTR(Unused);
DEF_SIMPLE_ATTR(Used);
DEF_SIMPLE_ATTR(Weak);
DEF_SIMPLE_ATTR(WeakImport);
DEF_SIMPLE_ATTR(WeakRef);
DEF_SIMPLE_ATTR(NoThrow);
DEF_SIMPLE_ATTR(Const);
DEF_SIMPLE_ATTR(Pure);
@ -543,7 +549,9 @@ class ReqdWorkGroupSizeAttr : public Attr {
};
// Checker-specific attributes.
DEF_SIMPLE_ATTR(CFReturnsNotRetained);
DEF_SIMPLE_ATTR(CFReturnsRetained);
DEF_SIMPLE_ATTR(NSReturnsNotRetained);
DEF_SIMPLE_ATTR(NSReturnsRetained);
// C++0x member checking attributes.

View File

@ -16,6 +16,7 @@
#include "clang/AST/DeclarationName.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "llvm/ADT/SmallVector.h"
@ -159,7 +160,11 @@ class CXXBasePaths {
friend class CXXRecordDecl;
void ComputeDeclsFound();
bool lookupInBases(ASTContext &Context,
const CXXRecordDecl *Record,
CXXRecordDecl::BaseMatchesCallback *BaseMatches,
void *UserData);
public:
typedef std::list<CXXBasePath>::iterator paths_iterator;
typedef std::list<CXXBasePath>::const_iterator const_paths_iterator;

View File

@ -120,6 +120,13 @@ class CanQual {
return Stored.isLocalRestrictQualified();
}
/// \brief Determines if this canonical type is furthermore
/// canonical as a parameter. The parameter-canonicalization
/// process decays arrays to pointers and drops top-level qualifiers.
bool isCanonicalAsParam() const {
return Stored.isCanonicalAsParam();
}
/// \brief Retrieve the unqualified form of this type.
CanQual<T> getUnqualifiedType() const;
@ -157,6 +164,10 @@ class CanQual {
/// ensure that the given type is a canonical type with the correct
// (dynamic) type.
static CanQual<T> CreateUnsafe(QualType Other);
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(getAsOpaquePtr());
}
};
template<typename T, typename U>
@ -172,6 +183,10 @@ inline bool operator!=(CanQual<T> x, CanQual<U> y) {
/// \brief Represents a canonical, potentially-qualified type.
typedef CanQual<Type> CanQualType;
inline CanQualType Type::getCanonicalTypeUnqualified() const {
return CanQualType::CreateUnsafe(getCanonicalTypeInternal());
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
CanQualType T) {
DB << static_cast<QualType>(T);
@ -547,18 +562,24 @@ struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> {
template<>
struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
};
template<>
struct CanProxyAdaptor<FunctionNoProtoType>
: public CanProxyBase<FunctionNoProtoType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
};
template<>
struct CanProxyAdaptor<FunctionProtoType>
: public CanProxyBase<FunctionProtoType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs)
CanQualType getArgType(unsigned i) const {
return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i));

View File

@ -267,8 +267,8 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
}
void setAnonymousNamespace(NamespaceDecl *D) {
assert(D->isAnonymousNamespace());
assert(D->getParent() == this);
assert(!D || D->isAnonymousNamespace());
assert(!D || D->getParent() == this);
AnonymousNamespace = D;
}
@ -561,7 +561,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// \brief Determine whether this is or was instantiated from an out-of-line
/// definition of a static data member.
bool isOutOfLine() const;
virtual bool isOutOfLine() const;
/// \brief If this is a static data member, find its out-of-line definition.
VarDecl *getOutOfLineDefinition();
@ -1306,7 +1306,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
/// \brief Determine whether this is or was instantiated from an out-of-line
/// definition of a member function.
bool isOutOfLine() const;
virtual bool isOutOfLine() const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }

View File

@ -279,7 +279,8 @@ class Decl {
/// \brief Whether this declaration was used, meaning that a definition
/// is required.
bool isUsed() const { return Used; }
bool isUsed() const;
void setUsed(bool U = true) { Used = U; }
/// \brief Retrieve the level of precompiled header from which this
@ -330,7 +331,7 @@ class Decl {
return const_cast<Decl*>(this)->getLexicalDeclContext();
}
bool isOutOfLine() const {
virtual bool isOutOfLine() const {
return getLexicalDeclContext() != getDeclContext();
}

View File

@ -710,7 +710,7 @@ class CXXRecordDecl : public RecordDecl {
CXXConstructorDecl *getDefaultConstructor(ASTContext &Context);
/// getDestructor - Returns the destructor decl for this class.
CXXDestructorDecl *getDestructor(ASTContext &Context);
CXXDestructorDecl *getDestructor(ASTContext &Context) const;
/// isLocalClass - If the class is a local class [class.local], returns
/// the enclosing function declaration.
@ -751,6 +751,21 @@ class CXXRecordDecl : public RecordDecl {
/// tangling input and output in \p Paths
bool isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const;
/// \brief Determine whether this class is virtually derived from
/// the class \p Base.
///
/// This routine only determines whether this class is virtually
/// derived from \p Base, but does not account for factors that may
/// make a Derived -> Base class ill-formed, such as
/// private/protected inheritance or multiple, ambiguous base class
/// subobjects.
///
/// \param Base the base class we are searching for.
///
/// \returns true if this class is virtually derived from Base,
/// false otherwise.
bool isVirtuallyDerivedFrom(CXXRecordDecl *Base) const;
/// \brief Determine whether this class is provably not derived from
/// the type \p Base.
bool isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const;
@ -824,6 +839,18 @@ class CXXRecordDecl : public RecordDecl {
/// base class that we are searching for.
static bool FindBaseClass(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, void *BaseRecord);
/// \brief Base-class lookup callback that determines whether the
/// given base class specifier refers to a specific class
/// declaration and describes virtual derivation.
///
/// This callback can be used with \c lookupInBases() to determine
/// whether a given derived class has is a virtual base class
/// subobject of a particular type. The user data pointer should
/// refer to the canonical CXXRecordDecl of the base class that we
/// are searching for.
static bool FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, void *BaseRecord);
/// \brief Base-class lookup callback that determines whether there exists
/// a tag with the given name.

View File

@ -494,11 +494,13 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
}
unsigned protocol_size() const { return ReferencedProtocols.size(); }
typedef ObjCList<ObjCIvarDecl>::iterator ivar_iterator;
ivar_iterator ivar_begin() const { return IVars.begin(); }
ivar_iterator ivar_end() const { return IVars.end(); }
unsigned ivar_size() const { return IVars.size(); }
bool ivar_empty() const { return IVars.empty(); }
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); }
ivar_iterator ivar_end() const { return ivar_iterator(decls_end()); }
unsigned ivar_size() const {
return std::distance(ivar_begin(), ivar_end());
}
bool ivar_empty() const { return ivar_begin() == ivar_end(); }
/// setProtocolList - Set the list of protocols that this interface
/// implements.
@ -514,10 +516,6 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
const SourceLocation *Locs,
ASTContext &C);
void setIVarList(ObjCIvarDecl * const *List, unsigned Num, ASTContext &C) {
IVars.set(List, Num, C);
}
bool isForwardDecl() const { return ForwardDecl; }
void setForwardDecl(bool val) { ForwardDecl = val; }
@ -529,6 +527,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
CategoryList = category;
}
ObjCCategoryDecl* getClassExtension() const;
/// isSuperClassOf - Return true if this class is the specified class or is a
/// super class of the specified interface class.
bool isSuperClassOf(const ObjCInterfaceDecl *I) const {
@ -951,6 +951,20 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
bool IsClassExtension() const { return getIdentifier() == 0; }
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
ivar_iterator ivar_begin() const {
return ivar_iterator(decls_begin());
}
ivar_iterator ivar_end() const {
return ivar_iterator(decls_end());
}
unsigned ivar_size() const {
return std::distance(ivar_begin(), ivar_end());
}
bool ivar_empty() const {
return ivar_begin() == ivar_end();
}
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation At) { AtLoc = At; }

View File

@ -150,7 +150,8 @@ class Expr : public Stmt {
LV_InvalidExpression,
LV_MemberFunction,
LV_SubObjCPropertySetting,
LV_SubObjCPropertyGetterSetting
LV_SubObjCPropertyGetterSetting,
LV_ClassTemporary
};
isLvalueResult isLvalue(ASTContext &Ctx) const;
@ -181,7 +182,8 @@ class Expr : public Stmt {
MLV_NoSetterProperty,
MLV_MemberFunction,
MLV_SubObjCPropertySetting,
MLV_SubObjCPropertyGetterSetting
MLV_SubObjCPropertyGetterSetting,
MLV_ClassTemporary
};
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
SourceLocation *Loc = 0) const;

View File

@ -997,21 +997,59 @@ class CXXDeleteExpr : public Expr {
virtual child_iterator child_end();
};
/// \brief Structure used to store the type being destroyed by a
/// pseudo-destructor expression.
class PseudoDestructorTypeStorage {
/// \brief Either the type source information or the name of the type, if
/// it couldn't be resolved due to type-dependence.
llvm::PointerUnion<TypeSourceInfo *, IdentifierInfo *> Type;
/// \brief The starting source location of the pseudo-destructor type.
SourceLocation Location;
public:
PseudoDestructorTypeStorage() { }
PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc)
: Type(II), Location(Loc) { }
PseudoDestructorTypeStorage(TypeSourceInfo *Info);
TypeSourceInfo *getTypeSourceInfo() const {
return Type.dyn_cast<TypeSourceInfo *>();
}
IdentifierInfo *getIdentifier() const {
return Type.dyn_cast<IdentifierInfo *>();
}
SourceLocation getLocation() const { return Location; }
};
/// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]).
///
/// Example:
/// A pseudo-destructor is an expression that looks like a member access to a
/// destructor of a scalar type, except that scalar types don't have
/// destructors. For example:
///
/// \code
/// template<typename T>
/// void destroy(T* ptr) {
/// ptr->~T();
/// typedef int T;
/// void f(int *p) {
/// p->T::~T();
/// }
/// \endcode
///
/// When the template is parsed, the expression \c ptr->~T will be stored as
/// a member reference expression. If it then instantiated with a scalar type
/// as a template argument for T, the resulting expression will be a
/// pseudo-destructor expression.
/// Pseudo-destructors typically occur when instantiating templates such as:
///
/// \code
/// template<typename T>
/// void destroy(T* ptr) {
/// ptr->T::~T();
/// }
/// \endcode
///
/// for scalar types. A pseudo-destructor expression has no run-time semantics
/// beyond evaluating the base expression.
class CXXPseudoDestructorExpr : public Expr {
/// \brief The base expression (that is being destroyed).
Stmt *Base;
@ -1030,28 +1068,44 @@ class CXXPseudoDestructorExpr : public Expr {
/// present.
SourceRange QualifierRange;
/// \brief The type being destroyed.
QualType DestroyedType;
/// \brief The location of the type after the '~'.
SourceLocation DestroyedTypeLoc;
/// \brief The type that precedes the '::' in a qualified pseudo-destructor
/// expression.
TypeSourceInfo *ScopeType;
/// \brief The location of the '::' in a qualified pseudo-destructor
/// expression.
SourceLocation ColonColonLoc;
/// \brief The location of the '~'.
SourceLocation TildeLoc;
/// \brief The type being destroyed, or its name if we were unable to
/// resolve the name.
PseudoDestructorTypeStorage DestroyedType;
public:
CXXPseudoDestructorExpr(ASTContext &Context,
Expr *Base, bool isArrow, SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
QualType DestroyedType,
SourceLocation DestroyedTypeLoc)
TypeSourceInfo *ScopeType,
SourceLocation ColonColonLoc,
SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
false, 0)),
/*isTypeDependent=*/false,
false, 0, false,
false, 0, 0, false,
CC_Default)),
/*isTypeDependent=*/(Base->isTypeDependent() ||
(DestroyedType.getTypeSourceInfo() &&
DestroyedType.getTypeSourceInfo()->getType()->isDependentType())),
/*isValueDependent=*/Base->isValueDependent()),
Base(static_cast<Stmt *>(Base)), IsArrow(isArrow),
OperatorLoc(OperatorLoc), Qualifier(Qualifier),
QualifierRange(QualifierRange), DestroyedType(DestroyedType),
DestroyedTypeLoc(DestroyedTypeLoc) { }
QualifierRange(QualifierRange),
ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc),
DestroyedType(DestroyedType) { }
void setBase(Expr *E) { Base = E; }
Expr *getBase() const { return cast<Expr>(Base); }
@ -1079,15 +1133,51 @@ class CXXPseudoDestructorExpr : public Expr {
/// \brief Retrieve the location of the '.' or '->' operator.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
/// \brief Retrieve the type that is being destroyed.
QualType getDestroyedType() const { return DestroyedType; }
/// \brief Retrieve the location of the type being destroyed.
SourceLocation getDestroyedTypeLoc() const { return DestroyedTypeLoc; }
virtual SourceRange getSourceRange() const {
return SourceRange(Base->getLocStart(), DestroyedTypeLoc);
/// \brief Retrieve the scope type in a qualified pseudo-destructor
/// expression.
///
/// Pseudo-destructor expressions can have extra qualification within them
/// that is not part of the nested-name-specifier, e.g., \c p->T::~T().
/// Here, if the object type of the expression is (or may be) a scalar type,
/// \p T may also be a scalar type and, therefore, cannot be part of a
/// nested-name-specifier. It is stored as the "scope type" of the pseudo-
/// destructor expression.
TypeSourceInfo *getScopeTypeInfo() const { return ScopeType; }
/// \brief Retrieve the location of the '::' in a qualified pseudo-destructor
/// expression.
SourceLocation getColonColonLoc() const { return ColonColonLoc; }
/// \brief Retrieve the location of the '~'.
SourceLocation getTildeLoc() const { return TildeLoc; }
/// \brief Retrieve the source location information for the type
/// being destroyed.
///
/// This type-source information is available for non-dependent
/// pseudo-destructor expressions and some dependent pseudo-destructor
/// expressions. Returns NULL if we only have the identifier for a
/// dependent pseudo-destructor expression.
TypeSourceInfo *getDestroyedTypeInfo() const {
return DestroyedType.getTypeSourceInfo();
}
/// \brief In a dependent pseudo-destructor expression for which we do not
/// have full type information on the destroyed type, provides the name
/// of the destroyed type.
IdentifierInfo *getDestroyedTypeIdentifier() const {
return DestroyedType.getIdentifier();
}
/// \brief Retrieve the type being destroyed.
QualType getDestroyedType() const;
/// \brief Retrieve the starting location of the type being destroyed.
SourceLocation getDestroyedTypeLoc() const {
return DestroyedType.getLocation();
}
virtual SourceRange getSourceRange() const;
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXPseudoDestructorExprClass;

View File

@ -90,9 +90,13 @@ namespace clang {
class TemplateArgument;
class TemplateArgumentLoc;
class TemplateArgumentListInfo;
class Type;
class QualifiedNameType;
struct PrintingPolicy;
template <typename> class CanQual;
typedef CanQual<Type> CanQualType;
// Provide forward declarations for all of the *Type classes
#define TYPE(Class, Base) class Class##Type;
#include "clang/AST/TypeNodes.def"
@ -976,7 +980,10 @@ class Type {
/// \brief Determine the linkage of this type.
virtual Linkage getLinkage() const;
QualType getCanonicalTypeInternal() const { return CanonicalType; }
QualType getCanonicalTypeInternal() const {
return CanonicalType;
}
CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
void dump() const;
static bool classof(const Type *) { return true; }
};

View File

@ -31,7 +31,11 @@
// type that is always dependent. Clients that do not need to deal
// with uninstantiated C++ templates can ignore these types.
//
// There is a fifth macro, independent of the others. Most clients
// NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that
// is non-canonical unless it is dependent. Defaults to TYPE because
// it is neither reliably dependent nor reliably non-canonical.
//
// There is a sixth macro, independent of the others. Most clients
// will not need to use it.
//
// LEAF_TYPE(Class) - A type that never has inner types. Clients
@ -51,6 +55,10 @@
# define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base)
#endif
#ifndef NON_CANONICAL_UNLESS_DEPENDENT_TYPE
# define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) TYPE(Class, Base)
#endif
TYPE(Builtin, Type)
TYPE(Complex, Type)
TYPE(Pointer, Type)
@ -72,16 +80,16 @@ TYPE(FunctionProto, FunctionType)
TYPE(FunctionNoProto, FunctionType)
DEPENDENT_TYPE(UnresolvedUsing, Type)
NON_CANONICAL_TYPE(Typedef, Type)
NON_CANONICAL_TYPE(TypeOfExpr, Type)
NON_CANONICAL_TYPE(TypeOf, Type)
NON_CANONICAL_TYPE(Decltype, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Decltype, Type)
ABSTRACT_TYPE(Tag, Type)
TYPE(Record, TagType)
TYPE(Enum, TagType)
NON_CANONICAL_TYPE(Elaborated, Type)
DEPENDENT_TYPE(TemplateTypeParm, Type)
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
TYPE(TemplateSpecialization, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
NON_CANONICAL_TYPE(QualifiedName, Type)
DEPENDENT_TYPE(Typename, Type)
TYPE(ObjCInterface, Type)
@ -101,6 +109,7 @@ LEAF_TYPE(TemplateTypeParm)
#undef LEAF_TYPE
#endif
#undef NON_CANONICAL_UNLESS_DEPENDENT_TYPE
#undef DEPENDENT_TYPE
#undef NON_CANONICAL_TYPE
#undef ABSTRACT_TYPE

View File

@ -75,11 +75,14 @@ class ConversionSpecifier {
VoidPtrArg, // 'p'
OutIntPtrArg, // 'n'
PercentArg, // '%'
// Objective-C specific specifiers.
// MacOS X unicode extensions.
CArg, // 'C'
UnicodeStrArg, // 'S'
// Objective-C specific specifiers.
ObjCObjArg, // '@'
// GlibC specific specifiers.
// GlibC specific specifiers.
PrintErrno, // 'm'
// Specifier ranges.
// Specifier ranges.
IntArgBeg = dArg,
IntArgEnd = iArg,
UIntArgBeg = oArg,
@ -147,20 +150,27 @@ enum LengthModifier {
class OptionalAmount {
public:
enum HowSpecified { NotSpecified, Constant, Arg };
enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
OptionalAmount(HowSpecified h, const char *st)
: start(st), hs(h), amt(0) {}
OptionalAmount(HowSpecified h, unsigned i, const char *st)
: start(st), hs(h), amt(i) {}
OptionalAmount()
: start(0), hs(NotSpecified), amt(0) {}
OptionalAmount(bool b = true)
: start(0), hs(b ? NotSpecified : Invalid), amt(0) {}
OptionalAmount(unsigned i, const char *st)
: start(st), hs(Constant), amt(i) {}
bool isInvalid() const {
return hs == Invalid;
}
HowSpecified getHowSpecified() const { return hs; }
bool hasDataArgument() const { return hs == Arg; }
unsigned getArgIndex() const {
assert(hasDataArgument());
return amt;
}
unsigned getConstantAmount() const {
assert(hs == Constant);
return amt;
@ -185,14 +195,19 @@ class FormatSpecifier {
unsigned HasSpacePrefix : 1;
unsigned HasAlternativeForm : 1;
unsigned HasLeadingZeroes : 1;
unsigned flags : 5;
/// Positional arguments, an IEEE extension:
/// IEEE Std 1003.1, 2004 Edition
/// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
unsigned UsesPositionalArg : 1;
unsigned argIndex;
ConversionSpecifier CS;
OptionalAmount FieldWidth;
OptionalAmount Precision;
public:
FormatSpecifier() : LM(None),
IsLeftJustified(0), HasPlusPrefix(0), HasSpacePrefix(0),
HasAlternativeForm(0), HasLeadingZeroes(0) {}
HasAlternativeForm(0), HasLeadingZeroes(0), UsesPositionalArg(0),
argIndex(0) {}
static FormatSpecifier Parse(const char *beg, const char *end);
@ -208,6 +223,17 @@ class FormatSpecifier {
void setHasSpacePrefix() { HasSpacePrefix = 1; }
void setHasAlternativeForm() { HasAlternativeForm = 1; }
void setHasLeadingZeros() { HasLeadingZeroes = 1; }
void setUsesPositionalArg() { UsesPositionalArg = 1; }
void setArgIndex(unsigned i) {
assert(CS.consumesDataArgument());
argIndex = i;
}
unsigned getArgIndex() const {
assert(CS.consumesDataArgument());
return argIndex;
}
// Methods for querying the format specifier.
@ -247,8 +273,11 @@ class FormatSpecifier {
bool hasAlternativeForm() const { return (bool) HasAlternativeForm; }
bool hasLeadingZeros() const { return (bool) HasLeadingZeroes; }
bool hasSpacePrefix() const { return (bool) HasSpacePrefix; }
bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
};
enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
class FormatStringHandler {
public:
FormatStringHandler() {}
@ -259,10 +288,15 @@ class FormatStringHandler {
virtual void HandleNullChar(const char *nullCharacter) {}
virtual void
virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
PositionContext p) {}
virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
virtual bool
HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen) {}
unsigned specifierLen) { return true; }
virtual bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
const char *startSpecifier,

View File

@ -0,0 +1,55 @@
//===- ReachableCode.h -----------------------------------------*- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// A flow-sensitive, path-insensitive analysis of unreachable code.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_REACHABLECODE_H
#define LLVM_CLANG_REACHABLECODE_H
#include "clang/Basic/SourceLocation.h"
//===----------------------------------------------------------------------===//
// Forward declarations.
//===----------------------------------------------------------------------===//
namespace llvm {
class BitVector;
}
namespace clang {
class AnalysisContext;
class CFGBlock;
}
//===----------------------------------------------------------------------===//
// API.
//===----------------------------------------------------------------------===//
namespace clang {
namespace reachable_code {
class Callback {
public:
virtual ~Callback() {}
virtual void HandleUnreachable(SourceLocation L, SourceRange R1,
SourceRange R2) = 0;
};
/// ScanReachableFromBlock - Mark all blocks reachable from Start.
/// Returns the total number of blocks that were marked reachable.
unsigned ScanReachableFromBlock(const CFGBlock &Start,
llvm::BitVector &Reachable);
void FindUnreachableCode(AnalysisContext &AC, Callback &CB);
}} // end namespace clang::reachable_code
#endif

View File

@ -110,6 +110,8 @@ class LocationContext : public llvm::FoldingSetNode {
const LocationContext *getParent() const { return Parent; }
bool isParentOf(const LocationContext *LC) const;
const Decl *getDecl() const { return getAnalysisContext()->getDecl(); }
CFG *getCFG() const { return getAnalysisContext()->getCFG(); }

View File

@ -245,8 +245,6 @@ class CFGBlock {
Stmt* getLabel() { return Label; }
const Stmt* getLabel() const { return Label; }
void reverseStmts();
unsigned getBlockID() const { return BlockID; }
void dump(const CFG *cfg, const LangOptions &LO) const;

View File

@ -26,6 +26,7 @@
namespace clang {
class LocationContext;
class FunctionDecl;
class ProgramPoint {
public:
@ -41,6 +42,8 @@ class ProgramPoint {
PostPurgeDeadSymbolsKind,
PostStmtCustomKind,
PostLValueKind,
CallEnterKind,
CallExitKind,
MinPostStmtKind = PostStmtKind,
MaxPostStmtKind = PostLValueKind };
@ -308,6 +311,36 @@ class BlockEdge : public ProgramPoint {
}
};
class CallEnter : public StmtPoint {
public:
// CallEnter uses the caller's location context.
CallEnter(const Stmt *S, const FunctionDecl *fd, const LocationContext *L)
: StmtPoint(S, fd, CallEnterKind, L, 0) {}
const Stmt *getCallExpr() const {
return static_cast<const Stmt *>(getData1());
}
const FunctionDecl *getCallee() const {
return static_cast<const FunctionDecl *>(getData2());
}
static bool classof(const ProgramPoint *Location) {
return Location->getKind() == CallEnterKind;
}
};
class CallExit : public StmtPoint {
public:
// CallExit uses the callee's location context.
CallExit(const Stmt *S, const LocationContext *L)
: StmtPoint(S, 0, CallExitKind, L, 0) {}
static bool classof(const ProgramPoint *Location) {
return Location->getKind() == CallExitKind;
}
};
} // end namespace clang

View File

@ -23,6 +23,7 @@
#include "llvm/Support/Allocator.h"
#include "llvm/ADT/PointerIntPair.h"
#include <algorithm>
#include <cstring>
namespace clang {

View File

@ -317,7 +317,7 @@ BUILTIN(__builtin_frob_return_addr, "v*v*", "n")
BUILTIN(__builtin_dwarf_cfa, "v*", "n")
BUILTIN(__builtin_init_dwarf_reg_size_table, "vv*", "n")
BUILTIN(__builtin_dwarf_sp_column, "Ui", "n")
BUILTIN(__builtin_extend_pointer, "iv*", "n")
BUILTIN(__builtin_extend_pointer, "ULLiv*", "n") // _Unwind_Word == uint64_t
// GCC Object size checking builtins
BUILTIN(__builtin_object_size, "zv*i", "n")

View File

@ -403,13 +403,6 @@ class Diagnostic {
/// \brief Clear out the current diagnostic.
void Clear() { CurDiagID = ~0U; }
/// Deserialize - Deserialize the first diagnostic within the memory
/// [Memory, MemoryEnd), producing a new diagnostic builder describing the
/// deserialized diagnostic. If the memory does not contain a
/// diagnostic, returns a diagnostic builder with no diagnostic ID.
DiagnosticBuilder Deserialize(FileManager &FM, SourceManager &SM,
const char *&Memory, const char *MemoryEnd);
private:
/// getDiagnosticMappingInfo - Return the mapping info currently set for the
/// specified builtin diagnostic. This returns the high bit encoding, or zero
@ -799,12 +792,54 @@ class DiagnosticInfo {
/// output buffer using the arguments stored in this diagnostic.
void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
llvm::SmallVectorImpl<char> &OutStr) const;
};
/**
* \brief Represents a diagnostic in a form that can be serialized and
* deserialized.
*/
class StoredDiagnostic {
Diagnostic::Level Level;
FullSourceLoc Loc;
std::string Message;
std::vector<SourceRange> Ranges;
std::vector<CodeModificationHint> FixIts;
public:
StoredDiagnostic();
StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info);
StoredDiagnostic(Diagnostic::Level Level, llvm::StringRef Message);
~StoredDiagnostic();
/// \brief Evaluates true when this object stores a diagnostic.
operator bool() const { return Message.size() > 0; }
Diagnostic::Level getLevel() const { return Level; }
const FullSourceLoc &getLocation() const { return Loc; }
llvm::StringRef getMessage() const { return Message; }
typedef std::vector<SourceRange>::const_iterator range_iterator;
range_iterator range_begin() const { return Ranges.begin(); }
range_iterator range_end() const { return Ranges.end(); }
unsigned range_size() const { return Ranges.size(); }
typedef std::vector<CodeModificationHint>::const_iterator fixit_iterator;
fixit_iterator fixit_begin() const { return FixIts.begin(); }
fixit_iterator fixit_end() const { return FixIts.end(); }
unsigned fixit_size() const { return FixIts.size(); }
/// Serialize - Serialize the given diagnostic (with its diagnostic
/// level) to the given stream. Serialization is a lossy operation,
/// since the specific diagnostic ID and any macro-instantiation
/// information is lost.
void Serialize(Diagnostic::Level DiagLevel, llvm::raw_ostream &OS) const;
void Serialize(llvm::raw_ostream &OS) const;
/// Deserialize - Deserialize the first diagnostic within the memory
/// [Memory, MemoryEnd), producing a new diagnostic builder describing the
/// deserialized diagnostic. If the memory does not contain a
/// diagnostic, returns a diagnostic builder with no diagnostic ID.
static StoredDiagnostic Deserialize(FileManager &FM, SourceManager &SM,
const char *&Memory, const char *MemoryEnd);
};
/// DiagnosticClient - This is an abstract interface implemented by clients of

View File

@ -53,6 +53,29 @@ def note_odr_number_of_bases : Note<
"class has %0 base %plural{1:class|:classes}0">;
def note_odr_enumerator : Note<"enumerator %0 with value %1 here">;
def note_odr_missing_enumerator : Note<"no corresponding enumerator here">;
def err_odr_ivar_type_inconsistent : Error<
"instance variable %0 declared with incompatible types in different "
"translation units (%1 vs. %2)">;
def err_odr_objc_superclass_inconsistent : Error<
"class %0 has incompatible superclasses">;
def note_odr_objc_superclass : Note<"inherits from superclass %0 here">;
def note_odr_objc_missing_superclass : Note<"no corresponding superclass here">;
def err_odr_objc_method_result_type_inconsistent : Error<
"%select{class|instance}0 method %1 has incompatible result types in "
"different translation units (%2 vs. %3)">;
def err_odr_objc_method_num_params_inconsistent : Error<
"%select{class|instance}0 method %1 has a different number of parameters in "
"different translation units (%2 vs. %3)">;
def err_odr_objc_method_param_type_inconsistent : Error<
"%select{class|instance}0 method %1 has a parameter with a different types "
"in different translation units (%2 vs. %3)">;
def err_odr_objc_method_variadic_inconsistent : Error<
"%select{class|instance}0 method %1 is variadic in one translation unit "
"and not variadic in another">;
def note_odr_objc_method_here : Note<
"%select{class|instance}0 method %1 also declared here">;
def err_odr_objc_property_type_inconsistent : Error<
"property %0 declared with incompatible types in different "
"translation units (%1 vs. %2)">;
def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">;
}

View File

@ -88,6 +88,8 @@ def warn_ignoring_ftabstop_value : Warning<
def warn_drv_missing_resource_library : Warning<
"missing resource library '%0', link may fail">;
def warn_drv_conflicting_deployment_targets : Warning<
"conflicting deployment targets, both MACOSX_DEPLOYMENT_TARGET '%0' and IPHONEOS_DEPLOYMENT_TARGET '%1' are present in environment">;
"conflicting deployment targets, both MACOSX_DEPLOYMENT_TARGET '%0' and IPHONEOS_DEPLOYMENT_TARGET '%1' are present in environment">;
def warn_drv_treating_input_as_cxx : Warning<
"treating '%0' input as '%1' when in C++ mode, this behavior is deprecated">;
}

View File

@ -82,7 +82,7 @@ def note_fixit_main_file_unchanged : Note<
def warn_fixit_no_changes : Note<
"FIX-IT detected errors it could not fix; no output will be generated">;
def err_fe_clang : Error<"error invoking%s: %s">, DefaultFatal;
def err_fe_invoking : Error<"error invoking%0: %1">, DefaultFatal;
// PCH reader
def err_relocatable_without_without_isysroot : Error<

View File

@ -18,11 +18,13 @@ def Implicit : DiagGroup<"implicit", [
// Empty DiagGroups: these are recognized by clang but ignored.
// Empty DiagGroups are recognized by clang but ignored.
def : DiagGroup<"address">;
def AddressOfTemporary : DiagGroup<"address-of-temporary">;
def : DiagGroup<"aggregate-return">;
def : DiagGroup<"attributes">;
def : DiagGroup<"bad-function-cast">;
def BadLiteral : DiagGroup<"bad-literal">;
def : DiagGroup<"c++-compat">;
def : DiagGroup<"cast-align">;
def : DiagGroup<"cast-qual">;
@ -119,7 +121,6 @@ def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
def : DiagGroup<"write-strings">;
def CharSubscript : DiagGroup<"char-subscripts">;
def ForceAlignArgPointer : DiagGroup<"force-align-arg-pointer">;
// Aggregation warning settings.
@ -180,4 +181,4 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
// A warning group for warnings that we want to have on by default in clang,
// but which aren't on by default in GCC.
def NonGCC : DiagGroup<"non-gcc",
[SignCompare, Conversion, ForceAlignArgPointer]>;
[SignCompare, Conversion, BadLiteral]>;

View File

@ -146,8 +146,6 @@ def err_missing_comma_before_ellipsis : Error<
def err_unexpected_typedef_ident : Error<
"unexpected type name %0: expected identifier">;
def err_expected_class_name : Error<"expected class name">;
def err_destructor_class_name : Error<
"expected the class name after '~' to name a destructor">;
def err_unspecified_vla_size_with_static : Error<
"'static' may not be used with an unspecified variable length array size">;
@ -247,8 +245,10 @@ def err_expected_catch : Error<"expected catch">;
def err_expected_lbrace_or_comma : Error<"expected '{' or ','">;
def err_using_namespace_in_class : Error<
"'using namespace' is not allowed in classes">;
def err_ident_in_pseudo_dtor_not_a_type : Error<
"identifier %0 in pseudo-destructor expression does not name a type">;
def err_destructor_tilde_identifier : Error<
"expected a class name after '~' to name a destructor">;
def err_destructor_template_id : Error<
"destructor name %0 does not refer to a template">;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
@ -300,6 +300,7 @@ def err_explicit_instantiation_with_definition : Error<
"explicit template instantiation cannot have a definition; if this "
"definition is meant to be an explicit specialization, add '<>' after the "
"'template' keyword">;
def err_enum_template : Error<"enumeration cannot be a template">;
// Constructor template diagnostics.
def err_out_of_line_constructor_template_id : Error<

View File

@ -29,10 +29,12 @@ def ext_null_pointer_expr_not_ice : Extension<
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
"predefined identifier is only valid inside function">;
def err_float_overflow : Error<
"magnitude of floating-point constant too large for type %0; maximum is %1">;
def err_float_underflow : Error<
"magnitude of floating-point constant too small for type %0; minimum is %1">;
def warn_float_overflow : Warning<
"magnitude of floating-point constant too large for type %0; maximum is %1">,
InGroup<BadLiteral>;
def warn_float_underflow : Warning<
"magnitude of floating-point constant too small for type %0; minimum is %1">,
InGroup<BadLiteral>;
// C99 Designated Initializers
def err_array_designator_negative : Error<
@ -253,6 +255,12 @@ def err_dup_implementation_category : Error<
"reimplementation of category %1 for class %0">;
def err_conflicting_ivar_type : Error<
"instance variable %0 has conflicting type: %1 vs %2">;
def err_duplicate_ivar_declaration : Error<
"instance variable is already declared">;
def warn_on_superclass_use : Warning<
"class implementation may not have super class">;
def err_non_private_ivar_declaration : Error<
"only private ivars may be declared in implementation">;
def err_conflicting_ivar_bitwidth : Error<
"instance variable %0 has conflicting bit-field width">;
def err_conflicting_ivar_name : Error<
@ -447,6 +455,8 @@ def err_qualified_member_nonclass : Error<
"qualified member access refers to a member in %0">;
def err_incomplete_member_access : Error<
"member access into incomplete type %0">;
def err_incomplete_type : Error<
"incomplete type %0 where a complete type is required">;
// C++ class members
def err_storageclass_invalid_for_member : Error<
@ -486,8 +496,7 @@ def err_implicit_object_parameter_init : Error<
def note_field_decl : Note<"member is declared here">;
def note_bitfield_decl : Note<"bit-field is declared here">;
def note_previous_decl : Note<
"%0 declared here">;
def note_previous_decl : Note<"%0 declared here">;
def note_member_synthesized_at : Note<
"implicit default %select{constructor|copy constructor|"
"copy assignment operator|destructor}0 for %1 first required here">;
@ -557,6 +566,10 @@ def err_destructor_typedef_name : Error<
"destructor cannot be declared using a typedef %0 of the class name">;
def err_destructor_name : Error<
"expected the class name after '~' to name the enclosing class">;
def err_destructor_class_name : Error<
"expected the class name after '~' to name a destructor">;
def err_ident_in_pseudo_dtor_not_a_type : Error<
"identifier %0 in pseudo-destructor expression does not name a type">;
// C++ initialization
def err_init_conversion_failed : Error<
@ -724,9 +737,6 @@ def err_attribute_aligned_not_power_of_two : Error<
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
"'%0' redeclared without %1 attribute: previous %1 ignored">;
def warn_attribute_ignored : Warning<"%0 attribute ignored">;
def warn_faap_attribute_ignored : Warning<
"force_align_arg_pointer used on function pointer; attribute ignored">,
InGroup<ForceAlignArgPointer>;
def warn_attribute_precede_definition : Warning<
"attribute declaration must precede definition">;
def warn_attribute_void_function : Warning<
@ -741,6 +751,12 @@ def err_attribute_weak_static : Error<
"weak declaration of '%0' must be public">;
def warn_attribute_weak_import_invalid_on_definition : Warning<
"'weak_import' attribute cannot be specified on a definition">;
def err_attribute_weakref_not_static : Error<
"weakref declaration of '%0' must be static">;
def err_attribute_weakref_not_global_context : Error<
"weakref declaration of '%0' must be in a global context">;
def err_attribute_weakref_without_alias : Error<
"weakref declaration of '%0' must also have an alias attribute">;
def warn_attribute_wrong_decl_type : Warning<
"%0 attribute only applies to %select{function|union|"
"variable and function|function or method|parameter|"
@ -846,8 +862,10 @@ def err_attribute_regparm_invalid_number : Error<
// Clang-Specific Attributes
def err_attribute_iboutlet : Error<
"'iboutlet' attribute can only be applied to instance variables or "
"iboutlet attribute can only be applied to instance variables or "
"properties">;
def err_attribute_ibaction: Error<
"ibaction attribute can only be applied to Objective-C instance methods">;
def err_attribute_overloadable_not_function : Error<
"'overloadable' attribute can only be applied to a function">;
def err_attribute_overloadable_missing : Error<
@ -1482,6 +1500,8 @@ def err_forward_ref_enum : Error<
"ISO C++ forbids forward references to 'enum' types">;
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
def err_misplaced_ivar : Error<"ivar may be placed in a class extension "
"in non-fragile-abi2 mode only">;
def ext_enum_value_not_int : Extension<
"ISO C restricts enumerator values to range of 'int' (%0 is too "
"%select{small|large}1)">;
@ -1572,6 +1592,8 @@ def err_indirect_goto_in_protected_scope : Error<
def err_addr_of_label_in_protected_scope : Error<
"address taken of label in protected scope, jump to it would have "
"unknown effect on scope">;
def note_protected_by_variable_init : Note<
"jump bypasses variable initialization">;
def note_protected_by_vla_typedef : Note<
"jump bypasses initialization of VLA typedef">;
def note_protected_by_vla : Note<
@ -1761,7 +1783,8 @@ def err_typecheck_incomplete_array_needs_initializer : Error<
def err_array_init_not_init_list : Error<
"array initializer must be an initializer "
"list%select{| or string literal}0">;
def warn_deprecated_string_literal_conversion : Warning<
"conversion from string literal to %0 is deprecated">;
def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">;
def err_typecheck_sclass_fscope : Error<
"illegal storage class on file-scoped variable">;
@ -1777,6 +1800,11 @@ def err_unqualified_pointer_member_function : Error<
"must explicitly qualify member function %0 when taking its address">;
def err_typecheck_invalid_lvalue_addrof : Error<
"address expression must be an lvalue or a function designator">;
def ext_typecheck_addrof_class_temporary : ExtWarn<
"taking the address of a temporary object of type %0">,
InGroup<DiagGroup<"address-of-temporary">>, DefaultError;
def err_typecheck_addrof_class_temporary : Error<
"taking the address of a temporary object of type %0">;
def err_typecheck_unary_expr : Error<
"invalid argument type %0 to unary expression">;
def err_typecheck_indirection_requires_pointer : Error<
@ -1807,6 +1835,9 @@ def ext_typecheck_cond_incompatible_operands : ExtWarn<
"incompatible operand types (%0 and %1)">;
def err_typecheck_comparison_of_distinct_pointers : Error<
"comparison of distinct pointer types (%0 and %1)">;
def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn<
"comparison of distinct pointer types (%0 and %1) uses non-standard "
"composite pointer type %2">;
def err_typecheck_vector_comparison : Error<
"comparison of vector types (%0 and %1) not supported yet">;
def err_typecheck_assign_const : Error<"read-only variable is not assignable">;
@ -1992,6 +2023,9 @@ def err_new_array_nonconst : Error<
"only the first dimension of an allocated array may have dynamic size">;
def err_new_paren_array_nonconst : Error<
"when type is in parentheses, array cannot have dynamic size">;
def err_placement_new_non_placement_delete : Error<
"'new' expression with placement arguments refers to non-placement "
"'operator delete'">;
def err_array_size_not_integral : Error<
"array size expression must have integral or enumerated type, not %0">;
def err_default_init_const : Error<
@ -2057,7 +2091,12 @@ def err_pseudo_dtor_call_with_args : Error<
def err_dtor_expr_without_call : Error<
"%select{destructor reference|pseudo-destructor expression}0 must be "
"called immediately with '()'">;
def err_pseudo_dtor_destructor_non_type : Error<
"%0 does not refer to a type name in pseudo-destructor expression; expected "
"the name of type %1">;
def err_pseudo_dtor_template : Error<
"specialization of template %0 does not refer to a scalar type in pseudo-"
"destructor expression">;
def err_invalid_use_of_function_type : Error<
"a function type is not allowed here">;
def err_invalid_use_of_array_type : Error<"an array type is not allowed here">;
@ -2226,6 +2265,9 @@ def err_typecheck_expect_scalar_operand : Error<
"operand of type %0 where arithmetic or pointer type is required">;
def err_typecheck_cond_incompatible_operands : Error<
"incompatible operand types (%0 and %1)">;
def ext_typecheck_cond_incompatible_operands_nonstandard : ExtWarn<
"incompatible operand types (%0 and %1) use non-standard composite pointer "
"type %2">;
def err_cast_selector_expr : Error<
"cannot type cast @selector expression">;
def warn_typecheck_cond_incompatible_pointers : ExtWarn<
@ -2486,8 +2528,8 @@ def warn_printf_write_back : Warning<
InGroup<FormatSecurity>;
def warn_printf_insufficient_data_args : Warning<
"more '%%' conversions than data arguments">, InGroup<Format>;
def warn_printf_too_many_data_args : Warning<
"more data arguments than format specifiers">, InGroup<FormatExtraArgs>;
def warn_printf_data_arg_not_used : Warning<
"data argument not used by format string">, InGroup<FormatExtraArgs>;
def warn_printf_invalid_conversion : Warning<
"invalid conversion specifier '%0'">, InGroup<Format>;
def warn_printf_incomplete_specifier : Warning<
@ -2497,6 +2539,15 @@ def warn_printf_missing_format_string : Warning<
def warn_printf_conversion_argument_type_mismatch : Warning<
"conversion specifies type %0 but the argument has type %1">,
InGroup<Format>;
def warn_printf_zero_positional_specifier : Warning<
"position arguments in format strings start counting at 1 (not 0)">,
InGroup<Format>;
def warn_printf_invalid_positional_specifier : Warning<
"invalid position specified for %select{field width|field precision}0">,
InGroup<Format>;
def warn_printf_mix_positional_nonpositional_args : Warning<
"cannot mix positional and non-positional arguments in format string">,
InGroup<Format>;
def warn_null_arg : Warning<
"null passed to a callee which requires a non-null argument">,
InGroup<NonNull>;
@ -2506,15 +2557,10 @@ def warn_printf_format_string_is_wide_literal : Warning<
"format string should not be a wide string">, InGroup<Format>;
def warn_printf_format_string_contains_null_char : Warning<
"format string contains '\\0' within the string body">, InGroup<Format>;
def warn_printf_asterisk_width_missing_arg : Warning<
"'*' specified field width is missing a matching 'int' argument">;
def warn_printf_asterisk_precision_missing_arg : Warning<
"'.*' specified field precision is missing a matching 'int' argument">;
def warn_printf_asterisk_width_wrong_type : Warning<
"field width should have type %0, but argument has type %1">,
InGroup<Format>;
def warn_printf_asterisk_precision_wrong_type : Warning<
"field precision should have type %0, but argument has type %1">,
def warn_printf_asterisk_missing_arg : Warning<
"'%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument">;
def warn_printf_asterisk_wrong_type : Warning<
"field %select{width|precision}0 should have type %1, but argument has type %2">,
InGroup<Format>;
def warn_printf_nonsensical_precision: Warning<
"precision used in '%0' conversion specifier (where it has no meaning)">,
@ -2571,7 +2617,8 @@ def err_case_not_in_switch : Error<"'case' statement not in switch statement">;
def warn_bool_switch_condition : Warning<
"switch condition is a bool">;
def warn_case_value_overflow : Warning<
"overflow converting case value to switch condition type (%0 to %1)">;
"overflow converting case value to switch condition type (%0 to %1)">,
InGroup<DiagGroup<"switch">>;
def err_duplicate_case : Error<"duplicate case value '%0'">;
def warn_case_empty_range : Warning<"empty case range specified">;
def warn_missing_cases : Warning<"enumeration value %0 not handled in switch">,
@ -2695,6 +2742,8 @@ def ext_c99_array_usage : Extension<
def err_c99_array_usage_cxx : Error<
"C99-specific array features are not permitted in C++">;
def note_getter_unavailable : Note<
"or because setter is declared here, but no getter method %0 is found">;
def err_invalid_protocol_qualifiers : Error<
"invalid protocol qualifiers on non-ObjC type">;
def warn_ivar_use_hidden : Warning<

View File

@ -59,7 +59,6 @@ class LangOptions {
unsigned POSIXThreads : 1; // Compiling with POSIX thread support
// (-pthread)
unsigned Blocks : 1; // block extension to C
unsigned BlockIntrospection: 1; // block have ObjC type encodings.
unsigned EmitAllDecls : 1; // Emit all declarations, even if
// they are unused.
unsigned MathErrno : 1; // Math functions must respect errno
@ -143,7 +142,6 @@ class LangOptions {
ThreadsafeStatics = 1;
POSIXThreads = 0;
Blocks = 0;
BlockIntrospection = 0;
EmitAllDecls = 0;
MathErrno = 1;
@ -156,7 +154,7 @@ class LangOptions {
OverflowChecking = 0;
ObjCGCBitmapPrint = 0;
InstantiationDepth = 99;
InstantiationDepth = 500;
Optimize = 0;
OptimizeSize = 0;

View File

@ -38,6 +38,13 @@ inline void Emit16(llvm::raw_ostream& Out, uint32_t V) {
assert((V >> 16) == 0);
}
inline void Emit24(llvm::raw_ostream& Out, uint32_t V) {
Out << (unsigned char)(V);
Out << (unsigned char)(V >> 8);
Out << (unsigned char)(V >> 16);
assert((V >> 24) == 0);
}
inline void Emit32(llvm::raw_ostream& Out, uint32_t V) {
Out << (unsigned char)(V);
Out << (unsigned char)(V >> 8);

View File

@ -147,12 +147,22 @@ class CheckerContext {
void addTransition(const GRState *state) {
assert(state);
// If the 'state' is not new, we need to check if the cached state 'ST'
// is new.
if (state != getState() || (ST && ST != B.GetState(Pred)))
GenerateNode(state, true);
else
Dst.Add(Pred);
}
// Generate a node with a new program point different from the one that will
// be created by the GRStmtNodeBuilder.
void addTransition(const GRState *state, ProgramPoint Loc) {
ExplodedNode *N = B.generateNode(Loc, state, Pred);
if (N)
addTransition(N);
}
void EmitReport(BugReport *R) {
Eng.getBugReporter().EmitReport(R);
}

View File

@ -40,6 +40,8 @@ class GRCoreEngine {
friend class GRIndirectGotoNodeBuilder;
friend class GRSwitchNodeBuilder;
friend class GREndPathNodeBuilder;
friend class GRCallEnterNodeBuilder;
friend class GRCallExitNodeBuilder;
GRSubEngine& SubEngine;
@ -67,6 +69,9 @@ class GRCoreEngine {
void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
ExplodedNode* Pred);
void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
unsigned Index, ExplodedNode *Pred);
void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
/// Get the initial state from the subengine.
const GRState* getInitialState(const LocationContext *InitLoc) {
@ -90,6 +95,9 @@ class GRCoreEngine {
void ProcessSwitch(GRSwitchNodeBuilder& Builder);
void ProcessCallEnter(GRCallEnterNodeBuilder &Builder);
void ProcessCallExit(GRCallExitNodeBuilder &Builder);
private:
GRCoreEngine(const GRCoreEngine&); // Do not implement.
GRCoreEngine& operator=(const GRCoreEngine&);
@ -130,7 +138,6 @@ class GRStmtNodeBuilder {
CFGBlock& B;
const unsigned Idx;
ExplodedNode* Pred;
ExplodedNode* LastNode;
GRStateManager& Mgr;
GRAuditor* Auditor;
@ -157,10 +164,6 @@ class GRStmtNodeBuilder {
ExplodedNode* getBasePredecessor() const { return Pred; }
ExplodedNode* getLastNode() const {
return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
}
// FIXME: This should not be exposed.
GRWorkList *getWorkList() { return Eng.WList; }
@ -194,6 +197,12 @@ class GRStmtNodeBuilder {
return generateNode(S, St, Pred, PointKind);
}
ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State,
ExplodedNode* Pred) {
HasGeneratedNode = true;
return generateNodeInternal(PP, State, Pred);
}
ExplodedNode*
generateNodeInternal(const ProgramPoint &PP, const GRState* State,
ExplodedNode* Pred);
@ -431,6 +440,8 @@ class GREndPathNodeBuilder {
ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
ExplodedNode *P = 0);
void GenerateCallExitNode(const GRState *state);
CFGBlock* getBlock() const { return &B; }
const GRState* getState() const {
@ -438,6 +449,60 @@ class GREndPathNodeBuilder {
}
};
class GRCallEnterNodeBuilder {
GRCoreEngine &Eng;
const ExplodedNode *Pred;
// The call site.
const Stmt *CE;
// The definition of callee.
const FunctionDecl *FD;
// The parent block of the CallExpr.
const CFGBlock *Block;
// The CFGBlock index of the CallExpr.
unsigned Index;
public:
GRCallEnterNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred,
const Stmt *s, const FunctionDecl *fd,
const CFGBlock *blk, unsigned idx)
: Eng(eng), Pred(pred), CE(s), FD(fd), Block(blk), Index(idx) {}
const GRState *getState() const { return Pred->getState(); }
const LocationContext *getLocationContext() const {
return Pred->getLocationContext();
}
const Stmt *getCallExpr() const { return CE; }
const FunctionDecl *getCallee() const { return FD; }
const CFGBlock *getBlock() const { return Block; }
unsigned getIndex() const { return Index; }
void GenerateNode(const GRState *state, const LocationContext *LocCtx);
};
class GRCallExitNodeBuilder {
GRCoreEngine &Eng;
const ExplodedNode *Pred;
public:
GRCallExitNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred)
: Eng(eng), Pred(pred) {}
const ExplodedNode *getPredecessor() const { return Pred; }
const GRState *getState() const { return Pred->getState(); }
void GenerateNode(const GRState *state);
};
} // end clang namespace
#endif

View File

@ -171,7 +171,13 @@ class GRExprEngine : public GRSubEngine {
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
void ProcessEndPath(GREndPathNodeBuilder& builder);
// Generate the entry node of the callee.
void ProcessCallEnter(GRCallEnterNodeBuilder &builder);
// Generate the first post callsite node.
void ProcessCallExit(GRCallExitNodeBuilder &builder);
/// EvalAssume - Callback function invoked by the ConstraintManager when
/// making assumptions about state values.
const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption);

View File

@ -16,25 +16,24 @@
// FIXME: Reduce the number of includes.
#include "clang/Checker/PathSensitive/Environment.h"
#include "clang/Checker/PathSensitive/Store.h"
#include "clang/Checker/PathSensitive/ConstraintManager.h"
#include "clang/Checker/PathSensitive/ValueManager.h"
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "llvm/Support/Casting.h"
#include "llvm/System/DataTypes.h"
#include "clang/Checker/PathSensitive/ConstraintManager.h"
#include "clang/Checker/PathSensitive/Environment.h"
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/Checker/PathSensitive/Store.h"
#include "clang/Checker/PathSensitive/ValueManager.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/DataTypes.h"
#include <functional>
namespace clang {
@ -77,16 +76,13 @@ class GRState : public llvm::FoldingSetNode {
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
private:
void operator=(const GRState& R) const;
void operator=(const GRState& R) const; // Do not implement.
friend class GRStateManager;
GRStateManager *StateMgr;
Environment Env;
Store St;
// FIXME: Make these private.
public:
GenericDataMap GDM;
public:

View File

@ -28,6 +28,8 @@ class GRBranchNodeBuilder;
class GRIndirectGotoNodeBuilder;
class GRSwitchNodeBuilder;
class GREndPathNodeBuilder;
class GRCallEnterNodeBuilder;
class GRCallExitNodeBuilder;
class LocationContext;
class GRSubEngine {
@ -64,6 +66,12 @@ class GRSubEngine {
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0;
// Generate the entry node of the callee.
virtual void ProcessCallEnter(GRCallEnterNodeBuilder &builder) = 0;
// Generate the first post callsite node.
virtual void ProcessCallExit(GRCallExitNodeBuilder &builder) = 0;
/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.

View File

@ -428,7 +428,6 @@ class BlockTextRegion : public CodeTextRegion {
/// which correspond to "code+data". The distinction is important, because
/// like a closure a block captures the values of externally referenced
/// variables.
/// BlockDataRegion - A region that represents code texts of blocks (closures).
class BlockDataRegion : public SubRegion {
friend class MemRegionManager;
const BlockTextRegion *BC;
@ -798,11 +797,10 @@ class MemRegionManager {
GlobalsSpaceRegion *globals;
const StackFrameContext *cachedStackLocalsFrame;
StackLocalsSpaceRegion *cachedStackLocalsRegion;
const StackFrameContext *cachedStackArgumentsFrame;
StackArgumentsSpaceRegion *cachedStackArgumentsRegion;
llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *>
StackLocalsSpaceRegions;
llvm::DenseMap<const StackFrameContext *, StackArgumentsSpaceRegion *>
StackArgumentsSpaceRegions;
HeapSpaceRegion *heap;
UnknownSpaceRegion *unknown;
@ -810,10 +808,7 @@ class MemRegionManager {
public:
MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a)
: C(c), A(a), globals(0),
cachedStackLocalsFrame(0), cachedStackLocalsRegion(0),
cachedStackArgumentsFrame(0), cachedStackArgumentsRegion(0),
heap(0), unknown(0), code(0) {}
: C(c), A(a), globals(0), heap(0), unknown(0), code(0) {}
~MemRegionManager();

View File

@ -89,27 +89,23 @@ class SymbolData : public SymExpr {
typedef const SymbolData* SymbolRef;
// A symbol representing the value of a MemRegion.
class SymbolRegionValue : public SymbolData {
const MemRegion *R;
// We may cast the region to another type, so the expected type of the symbol
// may be different from the region's original type.
QualType T;
const TypedRegion *R;
public:
SymbolRegionValue(SymbolID sym, const MemRegion *r, QualType t = QualType())
: SymbolData(RegionValueKind, sym), R(r), T(t) {}
SymbolRegionValue(SymbolID sym, const TypedRegion *r)
: SymbolData(RegionValueKind, sym), R(r) {}
const MemRegion* getRegion() const { return R; }
const TypedRegion* getRegion() const { return R; }
static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R,
QualType T) {
static void Profile(llvm::FoldingSetNodeID& profile, const TypedRegion* R) {
profile.AddInteger((unsigned) RegionValueKind);
profile.AddPointer(R);
T.Profile(profile);
}
virtual void Profile(llvm::FoldingSetNodeID& profile) {
Profile(profile, R, T);
Profile(profile, R);
}
void dumpToStream(llvm::raw_ostream &os) const;
@ -122,6 +118,7 @@ class SymbolRegionValue : public SymbolData {
}
};
// A symbol representing the result of an expression.
class SymbolConjured : public SymbolData {
const Stmt* S;
QualType T;
@ -161,6 +158,8 @@ class SymbolConjured : public SymbolData {
}
};
// A symbol representing the value of a MemRegion whose parent region has
// symbolic value.
class SymbolDerived : public SymbolData {
SymbolRef parentSymbol;
const TypedRegion *R;
@ -294,8 +293,8 @@ class SymbolManager {
static bool canSymbolicate(QualType T);
/// Make a unique symbol for MemRegion R according to its kind.
const SymbolRegionValue* getRegionValueSymbol(const MemRegion* R,
QualType T = QualType());
const SymbolRegionValue* getRegionValueSymbol(const TypedRegion* R);
const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
unsigned VisitCount,
const void* SymbolTag = 0);

View File

@ -94,8 +94,7 @@ class ValueManager {
DefinedOrUnknownSVal makeZeroVal(QualType T);
/// getRegionValueSymbolVal - make a unique symbol for value of R.
DefinedOrUnknownSVal getRegionValueSymbolVal(const MemRegion *R,
QualType T = QualType());
DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedRegion *R);
DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
const Expr *E, unsigned Count);

View File

@ -53,6 +53,8 @@ class CodeGenOptions {
unsigned UnwindTables : 1; /// Emit unwind tables.
unsigned VerifyModule : 1; /// Control whether the module should be run
/// through the LLVM Verifier.
unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
/// aliases to base ctors when possible.
/// The code model to use (-mcmodel).
std::string CodeModel;
@ -101,6 +103,7 @@ class CodeGenOptions {
UnrollLoops = 0;
UnwindTables = 0;
VerifyModule = 1;
CXXCtorDtorAliases = 0;
Inlining = NoInlining;
RelocationModel = "pic";

View File

@ -143,6 +143,8 @@ def mrelocation_model : Separate<"-mrelocation-model">,
HelpText<"The relocation model to use">;
def munwind_tables : Flag<"-munwind-tables">,
HelpText<"Generate unwinding tables for all functions">;
def mconstructor_aliases : Flag<"-mconstructor-aliases">,
HelpText<"Emit complete constructors and destructors as aliases when possible">;
def O : Joined<"-O">, HelpText<"Optimization level">;
def Os : Flag<"-Os">, HelpText<"Optimize for size">;

View File

@ -70,6 +70,9 @@ class Driver {
/// Default name for linked images (e.g., "a.out").
std::string DefaultImageName;
/// Driver title to use with help.
std::string DriverTitle;
/// Host information for the platform the driver is running as. This
/// will generally be the actual host platform, but not always.
const HostInfo *Host;
@ -137,6 +140,9 @@ class Driver {
void setCheckInputsExist(bool Value) { CheckInputsExist = Value; }
const std::string &getTitle() { return DriverTitle; }
void setTitle(std::string Value) { DriverTitle = Value; }
/// @}
/// @name Primary Functionality
/// @{

View File

@ -235,7 +235,6 @@ def fastcp : Flag<"-fastcp">, Group<f_Group>;
def fastf : Flag<"-fastf">, Group<f_Group>;
def fast : Flag<"-fast">, Group<f_Group>;
def fasynchronous_unwind_tables : Flag<"-fasynchronous-unwind-tables">, Group<f_Group>;
def fblock_introspection : Flag<"-fblock-introspection">, Group<f_Group>;
def fblocks : Flag<"-fblocks">, Group<f_Group>;
def fbootclasspath_EQ : Joined<"-fbootclasspath=">, Group<f_Group>;
def fbuiltin_strcat : Flag<"-fbuiltin-strcat">, Group<f_Group>;
@ -445,7 +444,7 @@ def multiply__defined : Separate<"-multiply_defined">;
def mwarn_nonportable_cfstrings : Flag<"-mwarn-nonportable-cfstrings">, Group<m_Group>;
def m_Separate : Separate<"-m">, Group<m_Group>;
def m_Joined : Joined<"-m">, Group<m_Group>;
def no_canonical_prefixes : Flag<"-no-canonical-prefixes">, Flags<[DriverOption, HelpHidden]>,
def no_canonical_prefixes : Flag<"-no-canonical-prefixes">, Flags<[HelpHidden]>,
HelpText<"Use relative instead of canonical paths">;
def no_cpp_precomp : Flag<"-no-cpp-precomp">;
def no_integrated_as : Flag<"-no-integrated-as">, Flags<[DriverOption]>;

View File

@ -80,6 +80,10 @@ namespace types {
/// getCompilationPhase - Return the \args N th compilation phase to
/// be done for this type.
phases::ID getCompilationPhase(ID Id, unsigned N);
/// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given
/// C type (used for clang++ emulation of g++ behaviour)
ID lookupCXXTypeForCType(ID Id);
} // end namespace types
} // end namespace driver

View File

@ -69,26 +69,6 @@ ASTConsumer *CreateObjCRewriter(const std::string &InFile,
const LangOptions &LOpts,
bool SilenceRewriteMacroWarning);
// LLVM code generator: uses the code generation backend to generate LLVM
// assembly. This runs optimizations depending on the CodeGenOptions
// parameter. The output depends on the Action parameter.
enum BackendAction {
Backend_EmitAssembly, // Emit native assembly files
Backend_EmitBC, // Emit LLVM bitcode files
Backend_EmitLL, // Emit human-readable LLVM assembly
Backend_EmitNothing, // Don't emit anything (benchmarking mode)
Backend_EmitObj // Emit native object files
};
ASTConsumer *CreateBackendConsumer(BackendAction Action,
Diagnostic &Diags,
const LangOptions &Features,
const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts,
bool TimePasses,
const std::string &ModuleID,
llvm::raw_ostream *OS,
llvm::LLVMContext& C);
/// CreateHTMLPrinter - Create an AST consumer which rewrites source code to
/// HTML with syntax highlighting suitable for viewing in a web-browser.
ASTConsumer *CreateHTMLPrinter(llvm::raw_ostream *OS, Preprocessor &PP,

View File

@ -18,6 +18,8 @@
#include "llvm/ADT/OwningPtr.h"
#include "clang/Basic/FileManager.h"
#include "clang/Index/ASTLocation.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/System/Path.h"
#include <string>
#include <vector>
#include <cassert>
@ -51,7 +53,6 @@ class ASTUnit {
llvm::OwningPtr<TargetInfo> Target;
llvm::OwningPtr<Preprocessor> PP;
llvm::OwningPtr<ASTContext> Ctx;
bool tempFile;
/// Optional owned invocation, just used to make the invocation used in
/// LoadFromCommandLine available.
@ -80,6 +81,14 @@ class ASTUnit {
// Critical optimization when using clang_getCursor().
ASTLocation LastLoc;
/// \brief The set of diagnostics produced when creating this
/// translation unit.
llvm::SmallVector<StoredDiagnostic, 4> Diagnostics;
/// \brief Temporary files that should be removed when the ASTUnit is
/// destroyed.
llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles;
ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT
ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT
@ -104,8 +113,13 @@ class ASTUnit {
const std::string &getOriginalSourceFileName();
const std::string &getPCHFileName();
void unlinkTemporaryFile() { tempFile = true; }
/// \brief Add a temporary file that the ASTUnit depends on.
///
/// This file will be erased when the ASTUnit is destroyed.
void addTemporaryFile(const llvm::sys::Path &TempFile) {
TemporaryFiles.push_back(TempFile);
}
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; }
@ -120,6 +134,15 @@ class ASTUnit {
return TopLevelDecls;
}
// Retrieve the diagnostics associated with this AST
typedef const StoredDiagnostic * diag_iterator;
diag_iterator diag_begin() const { return Diagnostics.begin(); }
diag_iterator diag_end() const { return Diagnostics.end(); }
unsigned diag_size() const { return Diagnostics.size(); }
llvm::SmallVector<StoredDiagnostic, 4> &getDiagnostics() {
return Diagnostics;
}
/// \brief A mapping from a file name to the memory buffer that stores the
/// remapped contents of that file.
typedef std::pair<std::string, const llvm::MemoryBuffer *> RemappedFile;
@ -136,7 +159,8 @@ class ASTUnit {
Diagnostic &Diags,
bool OnlyLocalDecls = false,
RemappedFile *RemappedFiles = 0,
unsigned NumRemappedFiles = 0);
unsigned NumRemappedFiles = 0,
bool CaptureDiagnostics = false);
/// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a
/// CompilerInvocation object.
@ -151,7 +175,8 @@ class ASTUnit {
// shouldn't need to specify them at construction time.
static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI,
Diagnostic &Diags,
bool OnlyLocalDecls = false);
bool OnlyLocalDecls = false,
bool CaptureDiagnostics = false);
/// LoadFromCommandLine - Create an ASTUnit from a vector of command line
/// arguments, which must specify exactly one source file.
@ -173,7 +198,8 @@ class ASTUnit {
llvm::StringRef ResourceFilesPath,
bool OnlyLocalDecls = false,
RemappedFile *RemappedFiles = 0,
unsigned NumRemappedFiles = 0);
unsigned NumRemappedFiles = 0,
bool CaptureDiagnostics = false);
};
} // namespace clang

View File

@ -0,0 +1,65 @@
//===--- CodeGenAction.h - LLVM Code Generation Frontend Action -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/FrontendAction.h"
#include "llvm/ADT/OwningPtr.h"
namespace llvm {
class Module;
}
namespace clang {
class CodeGenAction : public ASTFrontendAction {
private:
unsigned Act;
llvm::OwningPtr<llvm::Module> TheModule;
protected:
CodeGenAction(unsigned _Act);
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile);
virtual void EndSourceFileAction();
public:
~CodeGenAction();
/// takeModule - Take the generated LLVM module, for use after the action has
/// been run. The result may be null on failure.
llvm::Module *takeModule();
};
class EmitAssemblyAction : public CodeGenAction {
public:
EmitAssemblyAction();
};
class EmitBCAction : public CodeGenAction {
public:
EmitBCAction();
};
class EmitLLVMAction : public CodeGenAction {
public:
EmitLLVMAction();
};
class EmitLLVMOnlyAction : public CodeGenAction {
public:
EmitLLVMOnlyAction();
};
class EmitObjAction : public CodeGenAction {
public:
EmitObjAction();
};
}

View File

@ -158,46 +158,6 @@ class ASTMergeAction : public FrontendAction {
virtual bool hasCodeCompletionSupport() const;
};
//===----------------------------------------------------------------------===//
// Code Gen AST Actions
//===----------------------------------------------------------------------===//
class CodeGenAction : public ASTFrontendAction {
private:
unsigned Act;
protected:
CodeGenAction(unsigned _Act);
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile);
};
class EmitAssemblyAction : public CodeGenAction {
public:
EmitAssemblyAction();
};
class EmitBCAction : public CodeGenAction {
public:
EmitBCAction();
};
class EmitLLVMAction : public CodeGenAction {
public:
EmitLLVMAction();
};
class EmitLLVMOnlyAction : public CodeGenAction {
public:
EmitLLVMOnlyAction();
};
class EmitObjAction : public CodeGenAction {
public:
EmitObjAction();
};
//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//

View File

@ -524,7 +524,9 @@ namespace clang {
/// associates a declaration name with one or more declaration
/// IDs. This data is used when performing qualified name lookup
/// into a DeclContext via DeclContext::lookup.
DECL_CONTEXT_VISIBLE
DECL_CONTEXT_VISIBLE,
/// \brief A NamespaceDecl record.
DECL_NAMESPACE
};
/// \brief Record codes for each kind of statement or expression.

View File

@ -37,11 +37,19 @@ class TextDiagnosticPrinter : public DiagnosticClient {
unsigned LastCaretDiagnosticWasNote : 1;
unsigned OwnsOutputStream : 1;
/// A string to prefix to error messages.
std::string Prefix;
public:
TextDiagnosticPrinter(llvm::raw_ostream &os, const DiagnosticOptions &diags,
bool OwnsOutputStream = false);
virtual ~TextDiagnosticPrinter();
/// setPrefix - Set the diagnostic printer prefix string, which will be
/// printed at the start of any diagnostics. If empty, no prefix string is
/// used.
void setPrefix(std::string Value) { Prefix = Value; }
void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) {
LangOpts = &LO;
}

View File

@ -570,6 +570,12 @@ class Preprocessor {
/// if an internal buffer is returned.
unsigned getSpelling(const Token &Tok, const char *&Buffer) const;
/// getSpelling - This method is used to get the spelling of a token into a
/// SmallVector. Note that the returned StringRef may not point to the
/// supplied buffer if a copy can be avoided.
llvm::StringRef getSpelling(const Token &Tok,
llvm::SmallVectorImpl<char> &Buffer) const;
/// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant
/// with length 1, return the character.
char getSpellingOfSingleCharacterNumericConstant(const Token &Tok) const {

View File

@ -327,13 +327,26 @@ class Action : public ActionBase {
return false;
}
/// \brief Determine whether the given name refers to a non-type nested name
/// specifier, e.g., the name of a namespace or namespace alias.
///
/// This actual is used in the parsing of pseudo-destructor names to
/// distinguish a nested-name-specifier and a "type-name ::" when we
/// see the token sequence "X :: ~".
virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
SourceLocation IdLoc,
IdentifierInfo &II,
TypeTy *ObjectType) {
return false;
}
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::').
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
SourceLocation CCLoc) {
return 0;
}
/// \brief Parsed an identifier followed by '::' in a C++
/// nested-name-specifier.
///
@ -490,6 +503,12 @@ class Action : public ActionBase {
return;
}
/// \brief Note that the given declaration had an initializer that could not
/// be parsed.
virtual void ActOnInitializerError(DeclPtrTy Dcl) {
return;
}
/// FinalizeDeclaratorGroup - After a sequence of declarators are parsed, this
/// gives the actions implementation a chance to process the group as a whole.
virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec& DS,
@ -1075,7 +1094,7 @@ class Action : public ActionBase {
SourceLocation RLoc) {
return ExprEmpty();
}
/// \brief Parsed a member access expresion (C99 6.5.2.3, C++ [expr.ref])
/// of the form \c x.m or \c p->m.
///
@ -1473,6 +1492,18 @@ class Action : public ActionBase {
//===------------------------- C++ Expressions --------------------------===//
/// \brief Parsed a destructor name or pseudo-destructor name.
///
/// \returns the type being destructed.
virtual TypeTy *getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, const CXXScopeSpec &SS,
TypeTy *ObjectType,
bool EnteringContext) {
return getTypeName(II, NameLoc, S, &SS, false, ObjectType);
}
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
tok::TokenKind Kind,
@ -1594,12 +1625,66 @@ class Action : public ActionBase {
/// with the type into which name lookup should look to find the member in
/// the member access expression.
///
/// \param MayBePseudoDestructor Originally false. The action should
/// set this true if the expression may end up being a
/// pseudo-destructor expression, indicating to the parser that it
/// shoudl be parsed as a pseudo-destructor rather than as a member
/// access expression. Note that this should apply both when the
/// object type is a scalar and when the object type is dependent.
///
/// \returns the (possibly modified) \p Base expression
virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
TypeTy *&ObjectType) {
TypeTy *&ObjectType,
bool &MayBePseudoDestructor) {
return ExprEmpty();
}
/// \brief Parsed a C++ pseudo-destructor expression or a dependent
/// member access expression that has the same syntactic form as a
/// pseudo-destructor expression.
///
/// \param S The scope in which the member access expression occurs.
///
/// \param Base The expression in which a member is being accessed, e.g., the
/// "x" in "x.f".
///
/// \param OpLoc The location of the member access operator ("." or "->")
///
/// \param OpKind The kind of member access operator ("." or "->")
///
/// \param SS The nested-name-specifier that precedes the type names
/// in the grammar. Note that this nested-name-specifier will not
/// cover the last "type-name ::" in the grammar, because it isn't
/// necessarily a nested-name-specifier.
///
/// \param FirstTypeName The type name that follows the optional
/// nested-name-specifier but precedes the '::', e.g., the first
/// type-name in "type-name :: type-name". This type name may be
/// empty. This will be either an identifier or a template-id.
///
/// \param CCLoc The location of the '::' in "type-name ::
/// typename". May be invalid, if there is no \p FirstTypeName.
///
/// \param TildeLoc The location of the '~'.
///
/// \param SecondTypeName The type-name following the '~', which is
/// the name of the type being destroyed. This will be either an
/// identifier or a template-id.
///
/// \param HasTrailingLParen Whether the next token in the stream is
/// a left parentheses.
virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
UnqualifiedId &SecondTypeName,
bool HasTrailingLParen) {
return ExprEmpty();
}

View File

@ -51,7 +51,8 @@ class AttributeList {
AttributeList *Next, bool declspec = false, bool cxx0x = false);
~AttributeList();
enum Kind { // Please keep this list alphabetized.
enum Kind { // Please keep this list alphabetized.
AT_IBAction, // Clang-specific.
AT_IBOutlet, // Clang-specific.
AT_address_space,
AT_alias,
@ -88,8 +89,10 @@ class AttributeList {
AT_nsobject,
AT_objc_exception,
AT_override,
AT_cf_returns_retained, // Clang-specific.
AT_ns_returns_retained, // Clang-specific.
AT_cf_returns_not_retained, // Clang-specific.
AT_cf_returns_retained, // Clang-specific.
AT_ns_returns_not_retained, // Clang-specific.
AT_ns_returns_retained, // Clang-specific.
AT_objc_gc,
AT_overloadable, // Clang-specific.
AT_packed,
@ -106,6 +109,7 @@ class AttributeList {
AT_visibility,
AT_warn_unused_result,
AT_weak,
AT_weakref,
AT_weak_import,
AT_reqd_wg_size,
IgnoredAttribute,

View File

@ -320,86 +320,39 @@ class Parser {
/// This returns true if the token was annotated.
bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false);
/// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but only
/// annotates C++ scope specifiers. This returns true if the token was
/// annotated.
/// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but
/// only annotates C++ scope specifiers. This returns true if there
/// was an unrecoverable error.
bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
/// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens,
/// replacing them with the non-context-sensitive keywords. This returns
/// true if the token was replaced.
bool TryAltiVecToken(DeclSpec &DS, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID, bool &isInvalid) {
if (getLang().AltiVec) {
if (Tok.getIdentifierInfo() == Ident_vector) {
const Token nextToken = NextToken();
switch (nextToken.getKind()) {
case tok::kw_short:
case tok::kw_long:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_void:
case tok::kw_char:
case tok::kw_int:
case tok::kw_float:
case tok::kw_double:
case tok::kw_bool:
case tok::kw___pixel:
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
return true;
case tok::identifier:
if (nextToken.getIdentifierInfo() == Ident_pixel) {
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
return true;
}
break;
default:
break;
}
} else if ((Tok.getIdentifierInfo() == Ident_pixel) &&
DS.isTypeAltiVecVector()) {
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
return true;
}
}
return false;
const char *&PrevSpec, unsigned &DiagID,
bool &isInvalid) {
if (!getLang().AltiVec ||
(Tok.getIdentifierInfo() != Ident_vector &&
Tok.getIdentifierInfo() != Ident_pixel))
return false;
return TryAltiVecTokenOutOfLine(DS, Loc, PrevSpec, DiagID, isInvalid);
}
/// TryAltiVecVectorToken - Check for context-sensitive AltiVec vector
/// identifier token, replacing it with the non-context-sensitive __vector.
/// This returns true if the token was replaced.
bool TryAltiVecVectorToken() {
if (getLang().AltiVec) {
if (Tok.getIdentifierInfo() == Ident_vector) {
const Token nextToken = NextToken();
switch (nextToken.getKind()) {
case tok::kw_short:
case tok::kw_long:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_void:
case tok::kw_char:
case tok::kw_int:
case tok::kw_float:
case tok::kw_double:
case tok::kw_bool:
case tok::kw___pixel:
Tok.setKind(tok::kw___vector);
return true;
case tok::identifier:
if (nextToken.getIdentifierInfo() == Ident_pixel) {
Tok.setKind(tok::kw___vector);
return true;
}
break;
default:
break;
}
}
}
return false;
if (!getLang().AltiVec ||
Tok.getIdentifierInfo() != Ident_vector) return false;
return TryAltiVecVectorTokenOutOfLine();
}
bool TryAltiVecVectorTokenOutOfLine();
bool TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
bool &isInvalid);
/// TentativeParsingAction - An object that is used as a kind of "tentative
/// parsing transaction". It gets instantiated to mark the token position and
/// after the token consumption is done, Commit() or Revert() is called to
@ -849,6 +802,7 @@ class Parser {
DeclPtrTy ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
AttributeList *prefixAttrs = 0);
void ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
tok::ObjCKeywordKind visibility,
SourceLocation atLoc);
bool ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &P,
llvm::SmallVectorImpl<SourceLocation> &PLocs,
@ -962,7 +916,8 @@ class Parser {
bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
TypeTy *ObjectType,
bool EnteringContext);
bool EnteringContext,
bool *MayBePseudoDestructor = 0);
//===--------------------------------------------------------------------===//
// C++ 5.2p1: C++ Casts
@ -972,6 +927,13 @@ class Parser {
// C++ 5.2p1: C++ Type Identification
OwningExprResult ParseCXXTypeid();
//===--------------------------------------------------------------------===//
// C++ 5.2.4: C++ Pseudo-Destructor Expressions
OwningExprResult ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
tok::TokenKind OpKind,
CXXScopeSpec &SS,
Action::TypeTy *ObjectType);
//===--------------------------------------------------------------------===//
// C++ 9.3.2: C++ 'this' pointer
OwningExprResult ParseCXXThis();
@ -1153,7 +1115,7 @@ class Parser {
void ParseObjCTypeQualifierList(ObjCDeclSpec &DS);
void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS,
AccessSpecifier AS = AS_none);
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), AccessSpecifier AS = AS_none);
void ParseEnumBody(SourceLocation StartLoc, DeclPtrTy TagDecl);
void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
DeclPtrTy TagDecl);
@ -1172,6 +1134,11 @@ class Parser {
bool isDeclarationSpecifier();
bool isTypeSpecifierQualifier();
bool isTypeQualifier() const;
/// isKnownToBeTypeSpecifier - Return true if we know that the specified token
/// is definitely a type-specifier. Return false if it isn't part of a type
/// specifier or if we're not sure.
bool isKnownToBeTypeSpecifier(const Token &Tok) const;
/// isDeclarationStatement - Disambiguates between a declaration or an
/// expression statement, when parsing function bodies.
@ -1387,8 +1354,7 @@ class Parser {
//===--------------------------------------------------------------------===//
// C++ 9: classes [class] and C structs/unions.
TypeResult ParseClassName(SourceLocation &EndLocation,
const CXXScopeSpec *SS = 0,
bool DestrExpected = false);
const CXXScopeSpec *SS = 0);
void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
@ -1414,7 +1380,8 @@ class Parser {
SourceLocation NameLoc,
bool EnteringContext,
TypeTy *ObjectType,
UnqualifiedId &Id);
UnqualifiedId &Id,
bool AssumeTemplateId = false);
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
TypeTy *ObjectType,
UnqualifiedId &Result);

View File

@ -129,6 +129,9 @@ class Scope {
typedef llvm::SmallVector<Action::DeclPtrTy, 2> UsingDirectivesTy;
UsingDirectivesTy UsingDirectives;
/// \brief The number of errors at the start of the given scope.
unsigned NumErrorsAtStart;
public:
Scope(Scope *Parent, unsigned ScopeFlags) {
Init(Parent, ScopeFlags);
@ -208,6 +211,14 @@ class Scope {
void* getEntity() const { return Entity; }
void setEntity(void *E) { Entity = E; }
/// \brief Retrieve the number of errors that had been emitted when we
/// entered this scope.
unsigned getNumErrorsAtStart() const { return NumErrorsAtStart; }
void setNumErrorsAtStart(unsigned NumErrors) {
NumErrorsAtStart = NumErrors;
}
/// isClassScope - Return true if this scope is a class/struct/union scope.
bool isClassScope() const {
return (getFlags() & Scope::ClassScope);
@ -300,6 +311,7 @@ class Scope {
DeclsInScope.clear();
UsingDirectives.clear();
Entity = 0;
NumErrorsAtStart = 0;
}
};

View File

@ -59,6 +59,12 @@ ASTContext::~ASTContext() {
// Release the DenseMaps associated with DeclContext objects.
// FIXME: Is this the ideal solution?
ReleaseDeclContextMaps();
// Release all of the memory associated with overridden C++ methods.
for (llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::iterator
OM = OverriddenMethods.begin(), OMEnd = OverriddenMethods.end();
OM != OMEnd; ++OM)
OM->second.Destroy();
if (FreeMemory) {
// Deallocate all the types.
@ -319,6 +325,80 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
}
CXXMethodVector::iterator CXXMethodVector::begin() const {
if ((Storage & 0x01) == 0)
return reinterpret_cast<iterator>(&Storage);
vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
return &Vec->front();
}
CXXMethodVector::iterator CXXMethodVector::end() const {
if ((Storage & 0x01) == 0) {
if (Storage == 0)
return reinterpret_cast<iterator>(&Storage);
return reinterpret_cast<iterator>(&Storage) + 1;
}
vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
return &Vec->front() + Vec->size();
}
void CXXMethodVector::push_back(const CXXMethodDecl *Method) {
if (Storage == 0) {
// 0 -> 1 element.
Storage = reinterpret_cast<uintptr_t>(Method);
return;
}
vector_type *Vec;
if ((Storage & 0x01) == 0) {
// 1 -> 2 elements. Allocate a new vector and push the element into that
// vector.
Vec = new vector_type;
Vec->push_back(reinterpret_cast<const CXXMethodDecl *>(Storage));
Storage = reinterpret_cast<uintptr_t>(Vec) | 0x01;
} else
Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
// Add the new method to the vector.
Vec->push_back(Method);
}
void CXXMethodVector::Destroy() {
if (Storage & 0x01)
delete reinterpret_cast<vector_type *>(Storage & ~0x01);
Storage = 0;
}
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
= OverriddenMethods.find(Method);
if (Pos == OverriddenMethods.end())
return 0;
return Pos->second.begin();
}
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
= OverriddenMethods.find(Method);
if (Pos == OverriddenMethods.end())
return 0;
return Pos->second.end();
}
void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden) {
OverriddenMethods[Method].push_back(Overridden);
}
namespace {
class BeforeInTranslationUnit
: std::binary_function<SourceRange, SourceRange, bool> {
@ -563,6 +643,12 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) {
Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
}
if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) {
// In the case of a field in a packed struct, we want the minimum
// of the alignment of the field and the alignment of the struct.
Align = std::min(Align,
getPreferredTypeAlign(FD->getParent()->getTypeForDecl()));
}
}
return CharUnits::fromQuantity(Align / Target.getCharWidth());
@ -872,14 +958,13 @@ void ASTContext::CollectObjCIvars(const ObjCInterfaceDecl *OI,
/// Collect all ivars, including those synthesized, in the current class.
///
void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars,
bool CollectSynthesized) {
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(),
E = OI->ivar_end(); I != E; ++I) {
Ivars.push_back(*I);
}
if (CollectSynthesized)
CollectSynthesizedIvars(OI, Ivars);
CollectNonClassIvars(OI, Ivars);
}
void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
@ -895,11 +980,20 @@ void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
CollectProtocolSynthesizedIvars(*P, Ivars);
}
/// CollectSynthesizedIvars -
/// This routine collect synthesized ivars for the designated class.
/// CollectNonClassIvars -
/// This routine collects all other ivars which are not declared in the class.
/// This includes synthesized ivars and those in class's implementation.
///
void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
// Find ivars declared in class extension.
if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) {
for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
E = CDecl->ivar_end(); I != E; ++I) {
Ivars.push_back(*I);
}
}
for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(),
E = OI->prop_end(); I != E; ++I) {
if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl())
@ -912,6 +1006,13 @@ void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
ObjCProtocolDecl *PD = (*P);
CollectProtocolSynthesizedIvars(PD, Ivars);
}
// Also add any ivar defined in this class's implementation
if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) {
for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
E = ImplDecl->ivar_end(); I != E; ++I)
Ivars.push_back(*I);
}
}
/// CollectInheritedProtocols - Collect all protocols in current class and
@ -924,9 +1025,11 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
ObjCProtocolDecl *Proto = (*P);
Protocols.insert(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
PE = Proto->protocol_end(); P != PE; ++P) {
Protocols.insert(*P);
CollectInheritedProtocols(*P, Protocols);
}
}
// Categories of this Interface.
for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList();
@ -4401,7 +4504,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
if (allRTypes) return rhs;
return getFunctionType(retType, proto->arg_type_begin(),
proto->getNumArgs(), proto->isVariadic(),
proto->getTypeQuals(), NoReturn, lcc);
proto->getTypeQuals(),
false, false, 0, 0, NoReturn, lcc);
}
if (allLTypes) return lhs;
@ -4498,6 +4602,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
switch (LHSClass) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
@ -4620,9 +4725,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return QualType();
}
case Type::TemplateSpecialization:
assert(false && "Dependent types have no size");
break;
}
return QualType();
@ -4888,8 +4990,11 @@ QualType ASTContext::GetBuiltinType(unsigned id,
// handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);".
if (ArgTypes.size() == 0 && TypeStr[0] == '.')
return getFunctionNoProtoType(ResType);
// FIXME: Should we create noreturn types?
return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
TypeStr[0] == '.', 0);
TypeStr[0] == '.', 0, false, false, 0, 0,
false, CC_Default);
}
QualType

File diff suppressed because it is too large Load Diff

View File

@ -74,37 +74,40 @@ void NonNullAttr::Destroy(ASTContext &C) {
// FIXME: Can we use variadic macro to define DEF_SIMPLE_ATTR_CLONE for
// "non-simple" classes?
DEF_SIMPLE_ATTR_CLONE(Packed)
DEF_SIMPLE_ATTR_CLONE(AlwaysInline)
DEF_SIMPLE_ATTR_CLONE(Malloc)
DEF_SIMPLE_ATTR_CLONE(NoReturn)
DEF_SIMPLE_ATTR_CLONE(AnalyzerNoReturn)
DEF_SIMPLE_ATTR_CLONE(BaseCheck)
DEF_SIMPLE_ATTR_CLONE(CDecl)
DEF_SIMPLE_ATTR_CLONE(CFReturnsNotRetained)
DEF_SIMPLE_ATTR_CLONE(CFReturnsRetained)
DEF_SIMPLE_ATTR_CLONE(Const)
DEF_SIMPLE_ATTR_CLONE(DLLExport)
DEF_SIMPLE_ATTR_CLONE(DLLImport)
DEF_SIMPLE_ATTR_CLONE(Deprecated)
DEF_SIMPLE_ATTR_CLONE(FastCall)
DEF_SIMPLE_ATTR_CLONE(Final)
DEF_SIMPLE_ATTR_CLONE(Hiding)
DEF_SIMPLE_ATTR_CLONE(Malloc)
DEF_SIMPLE_ATTR_CLONE(NSReturnsNotRetained)
DEF_SIMPLE_ATTR_CLONE(NSReturnsRetained)
DEF_SIMPLE_ATTR_CLONE(NoDebug)
DEF_SIMPLE_ATTR_CLONE(NoInline)
DEF_SIMPLE_ATTR_CLONE(NoReturn)
DEF_SIMPLE_ATTR_CLONE(NoThrow)
DEF_SIMPLE_ATTR_CLONE(ObjCException)
DEF_SIMPLE_ATTR_CLONE(ObjCNSObject)
DEF_SIMPLE_ATTR_CLONE(Override)
DEF_SIMPLE_ATTR_CLONE(Packed)
DEF_SIMPLE_ATTR_CLONE(Pure)
DEF_SIMPLE_ATTR_CLONE(StdCall)
DEF_SIMPLE_ATTR_CLONE(TransparentUnion)
DEF_SIMPLE_ATTR_CLONE(Unavailable)
DEF_SIMPLE_ATTR_CLONE(Unused)
DEF_SIMPLE_ATTR_CLONE(Used)
DEF_SIMPLE_ATTR_CLONE(WarnUnusedResult)
DEF_SIMPLE_ATTR_CLONE(Weak)
DEF_SIMPLE_ATTR_CLONE(WeakImport)
DEF_SIMPLE_ATTR_CLONE(NoThrow)
DEF_SIMPLE_ATTR_CLONE(Const)
DEF_SIMPLE_ATTR_CLONE(Pure)
DEF_SIMPLE_ATTR_CLONE(FastCall)
DEF_SIMPLE_ATTR_CLONE(StdCall)
DEF_SIMPLE_ATTR_CLONE(CDecl)
DEF_SIMPLE_ATTR_CLONE(TransparentUnion)
DEF_SIMPLE_ATTR_CLONE(ObjCNSObject)
DEF_SIMPLE_ATTR_CLONE(ObjCException)
DEF_SIMPLE_ATTR_CLONE(NoDebug)
DEF_SIMPLE_ATTR_CLONE(WarnUnusedResult)
DEF_SIMPLE_ATTR_CLONE(NoInline)
DEF_SIMPLE_ATTR_CLONE(CFReturnsRetained)
DEF_SIMPLE_ATTR_CLONE(NSReturnsRetained)
DEF_SIMPLE_ATTR_CLONE(BaseCheck)
DEF_SIMPLE_ATTR_CLONE(Hiding)
DEF_SIMPLE_ATTR_CLONE(Override)
DEF_SIMPLE_ATTR_CLONE(DLLImport)
DEF_SIMPLE_ATTR_CLONE(DLLExport)
DEF_SIMPLE_ATTR_CLONE(WeakRef)
DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer)
Attr* PragmaPackAttr::clone(ASTContext &C) const {
@ -139,6 +142,10 @@ Attr *IBOutletAttr::clone(ASTContext &C) const {
return ::new (C) IBOutletAttr;
}
Attr *IBActionAttr::clone(ASTContext &C) const {
return ::new (C) IBActionAttr;
}
Attr *GNUInlineAttr::clone(ASTContext &C) const {
return ::new (C) GNUInlineAttr;
}
@ -190,5 +197,3 @@ Attr *ReqdWorkGroupSizeAttr::clone(ASTContext &C) const {
Attr *MSP430InterruptAttr::clone(ASTContext &C) const {
return ::new (C) MSP430InterruptAttr(Number);
}

View File

@ -90,6 +90,17 @@ bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) cons
return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths);
}
bool CXXRecordDecl::isVirtuallyDerivedFrom(CXXRecordDecl *Base) const {
CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
/*DetectVirtual=*/false);
if (getCanonicalDecl() == Base->getCanonicalDecl())
return false;
Paths.setOrigin(const_cast<CXXRecordDecl*>(this));
return lookupInBases(&FindVirtualBaseClass, Base->getCanonicalDecl(), Paths);
}
static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) {
// OpaqueTarget is a CXXRecordDecl*.
return Base->getCanonicalDecl() != (const CXXRecordDecl*) OpaqueTarget;
@ -140,18 +151,20 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
return AllMatches;
}
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
void *UserData,
CXXBasePaths &Paths) const {
bool CXXBasePaths::lookupInBases(ASTContext &Context,
const CXXRecordDecl *Record,
CXXRecordDecl::BaseMatchesCallback *BaseMatches,
void *UserData) {
bool FoundPath = false;
// The access of the path down to this record.
AccessSpecifier AccessToHere = Paths.ScratchPath.Access;
bool IsFirstStep = Paths.ScratchPath.empty();
AccessSpecifier AccessToHere = ScratchPath.Access;
bool IsFirstStep = ScratchPath.empty();
ASTContext &Context = getASTContext();
for (base_class_const_iterator BaseSpec = bases_begin(),
BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) {
for (CXXRecordDecl::base_class_const_iterator BaseSpec = Record->bases_begin(),
BaseSpecEnd = Record->bases_end();
BaseSpec != BaseSpecEnd;
++BaseSpec) {
// Find the record of the base class subobjects for this type.
QualType BaseType = Context.getCanonicalType(BaseSpec->getType())
.getUnqualifiedType();
@ -167,31 +180,31 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
// Determine whether we need to visit this base class at all,
// updating the count of subobjects appropriately.
std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType];
bool VisitBase = true;
bool SetVirtual = false;
if (BaseSpec->isVirtual()) {
VisitBase = !Subobjects.first;
Subobjects.first = true;
if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
if (isDetectingVirtual() && DetectedVirtual == 0) {
// If this is the first virtual we find, remember it. If it turns out
// there is no base path here, we'll reset it later.
Paths.DetectedVirtual = BaseType->getAs<RecordType>();
DetectedVirtual = BaseType->getAs<RecordType>();
SetVirtual = true;
}
} else
++Subobjects.second;
if (Paths.isRecordingPaths()) {
if (isRecordingPaths()) {
// Add this base specifier to the current path.
CXXBasePathElement Element;
Element.Base = &*BaseSpec;
Element.Class = this;
Element.Class = Record;
if (BaseSpec->isVirtual())
Element.SubobjectNumber = 0;
else
Element.SubobjectNumber = Subobjects.second;
Paths.ScratchPath.push_back(Element);
ScratchPath.push_back(Element);
// Calculate the "top-down" access to this base class.
// The spec actually describes this bottom-up, but top-down is
@ -209,22 +222,22 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
// 3. Otherwise, overall access is determined by the most restrictive
// access in the sequence.
if (IsFirstStep)
Paths.ScratchPath.Access = BaseSpec->getAccessSpecifier();
ScratchPath.Access = BaseSpec->getAccessSpecifier();
else
Paths.ScratchPath.Access
= MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier());
ScratchPath.Access = CXXRecordDecl::MergeAccess(AccessToHere,
BaseSpec->getAccessSpecifier());
}
// Track whether there's a path involving this specific base.
bool FoundPathThroughBase = false;
if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) {
if (BaseMatches(BaseSpec, ScratchPath, UserData)) {
// We've found a path that terminates at this base.
FoundPath = FoundPathThroughBase = true;
if (Paths.isRecordingPaths()) {
if (isRecordingPaths()) {
// We have a path. Make a copy of it before moving on.
Paths.Paths.push_back(Paths.ScratchPath);
} else if (!Paths.isFindingAmbiguities()) {
Paths.push_back(ScratchPath);
} else if (!isFindingAmbiguities()) {
// We found a path and we don't care about ambiguities;
// return immediately.
return FoundPath;
@ -233,7 +246,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
CXXRecordDecl *BaseRecord
= cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>()
->getDecl());
if (BaseRecord->lookupInBases(BaseMatches, UserData, Paths)) {
if (lookupInBases(Context, BaseRecord, BaseMatches, UserData)) {
// C++ [class.member.lookup]p2:
// A member name f in one sub-object B hides a member name f in
// a sub-object A if A is a base class sub-object of B. Any
@ -243,29 +256,96 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
// There is a path to a base class that meets the criteria. If we're
// not collecting paths or finding ambiguities, we're done.
FoundPath = FoundPathThroughBase = true;
if (!Paths.isFindingAmbiguities())
if (!isFindingAmbiguities())
return FoundPath;
}
}
// Pop this base specifier off the current path (if we're
// collecting paths).
if (Paths.isRecordingPaths()) {
Paths.ScratchPath.pop_back();
if (isRecordingPaths()) {
ScratchPath.pop_back();
}
// If we set a virtual earlier, and this isn't a path, forget it again.
if (SetVirtual && !FoundPathThroughBase) {
Paths.DetectedVirtual = 0;
DetectedVirtual = 0;
}
}
// Reset the scratch path access.
Paths.ScratchPath.Access = AccessToHere;
ScratchPath.Access = AccessToHere;
return FoundPath;
}
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
void *UserData,
CXXBasePaths &Paths) const {
// If we didn't find anything, report that.
if (!Paths.lookupInBases(getASTContext(), this, BaseMatches, UserData))
return false;
// If we're not recording paths or we won't ever find ambiguities,
// we're done.
if (!Paths.isRecordingPaths() || !Paths.isFindingAmbiguities())
return true;
// C++ [class.member.lookup]p6:
// When virtual base classes are used, a hidden declaration can be
// reached along a path through the sub-object lattice that does
// not pass through the hiding declaration. This is not an
// ambiguity. The identical use with nonvirtual base classes is an
// ambiguity; in that case there is no unique instance of the name
// that hides all the others.
//
// FIXME: This is an O(N^2) algorithm, but DPG doesn't see an easy
// way to make it any faster.
for (CXXBasePaths::paths_iterator P = Paths.begin(), PEnd = Paths.end();
P != PEnd; /* increment in loop */) {
bool Hidden = false;
for (CXXBasePath::iterator PE = P->begin(), PEEnd = P->end();
PE != PEEnd && !Hidden; ++PE) {
if (PE->Base->isVirtual()) {
CXXRecordDecl *VBase = 0;
if (const RecordType *Record = PE->Base->getType()->getAs<RecordType>())
VBase = cast<CXXRecordDecl>(Record->getDecl());
if (!VBase)
break;
// The declaration(s) we found along this path were found in a
// subobject of a virtual base. Check whether this virtual
// base is a subobject of any other path; if so, then the
// declaration in this path are hidden by that patch.
for (CXXBasePaths::paths_iterator HidingP = Paths.begin(),
HidingPEnd = Paths.end();
HidingP != HidingPEnd;
++HidingP) {
CXXRecordDecl *HidingClass = 0;
if (const RecordType *Record
= HidingP->back().Base->getType()->getAs<RecordType>())
HidingClass = cast<CXXRecordDecl>(Record->getDecl());
if (!HidingClass)
break;
if (HidingClass->isVirtuallyDerivedFrom(VBase)) {
Hidden = true;
break;
}
}
}
}
if (Hidden)
P = Paths.Paths.erase(P);
else
++P;
}
return true;
}
bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *BaseRecord) {
@ -275,6 +355,16 @@ bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier,
->getCanonicalDecl() == BaseRecord;
}
bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *BaseRecord) {
assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord &&
"User data for FindBaseClass is not canonical!");
return Specifier->isVirtual() &&
Specifier->getType()->getAs<RecordType>()->getDecl()
->getCanonicalDecl() == BaseRecord;
}
bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {

View File

@ -680,12 +680,12 @@ const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const {
}
bool VarDecl::isOutOfLine() const {
if (!isStaticDataMember())
return false;
if (Decl::isOutOfLine())
return true;
if (!isStaticDataMember())
return false;
// If this static data member was instantiated from a static data member of
// a class template, check whether that static data member was defined
// out-of-line.

View File

@ -194,6 +194,24 @@ ASTContext &Decl::getASTContext() const {
return getTranslationUnitDecl()->getASTContext();
}
bool Decl::isUsed() const {
if (Used)
return true;
// Check for used attribute.
if (hasAttr<UsedAttr>())
return true;
// Check redeclarations for used attribute.
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
if (I->hasAttr<UsedAttr>() || I->Used)
return true;
}
return false;
}
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
case Function:
@ -418,7 +436,8 @@ void Decl::CheckAccessDeclContext() const {
// FunctionDecl)
// 4. the context is not a record
if (isa<TranslationUnitDecl>(this) ||
!isa<CXXRecordDecl>(getDeclContext()))
!isa<CXXRecordDecl>(getDeclContext()) ||
isInvalidDecl())
return;
assert(Access != AS_none &&

View File

@ -94,9 +94,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// Keep track of inherited vbases for this base class.
const CXXBaseSpecifier *Base = Bases[i];
QualType BaseType = Base->getType();
// Skip template types.
// FIXME. This means that this list must be rebuilt during template
// instantiation.
// Skip dependent types; we can't do any checking on them now.
if (BaseType->isDependentType())
continue;
CXXRecordDecl *BaseClassDecl
@ -143,6 +141,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().NumVBases = vbaseCount;
for (int i = 0; i < vbaseCount; i++) {
QualType QT = UniqueVbases[i]->getType();
// Skip dependent types; we can't do any checking on them now.
if (QT->isDependentType())
continue;
CXXRecordDecl *VBaseClassDecl
= cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl());
data().VBases[i] =
@ -543,14 +544,14 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
return 0;
}
CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) {
CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) const {
QualType ClassType = Context.getTypeDeclType(this);
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(
Context.getCanonicalType(ClassType));
DeclContext::lookup_iterator I, E;
DeclContext::lookup_const_iterator I, E;
llvm::tie(I, E) = lookup(Name);
assert(I != E && "Did not find a destructor!");
@ -573,7 +574,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
if (getOverloadedOperator() != OO_Delete &&
getOverloadedOperator() != OO_Array_Delete)
return false;
// C++ [basic.stc.dynamic.deallocation]p2:
// A template instance is never a usual deallocation function,
// regardless of its signature.
if (getPrimaryTemplate())
return false;
// C++ [basic.stc.dynamic.deallocation]p2:
// If a class T has a member deallocation function named operator delete
// with exactly one parameter, then that function is a usual (non-placement)
@ -604,51 +611,20 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
return true;
}
typedef llvm::DenseMap<const CXXMethodDecl*,
std::vector<const CXXMethodDecl *> *>
OverriddenMethodsMapTy;
// FIXME: We hate static data. This doesn't survive PCH saving/loading, and
// the vtable building code uses it at CG time.
static OverriddenMethodsMapTy *OverriddenMethods = 0;
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
assert(!MD->getParent()->isDependentContext() &&
"Can't add an overridden method to a class template!");
// FIXME: The CXXMethodDecl dtor needs to remove and free the entry.
if (!OverriddenMethods)
OverriddenMethods = new OverriddenMethodsMapTy();
std::vector<const CXXMethodDecl *> *&Methods = (*OverriddenMethods)[this];
if (!Methods)
Methods = new std::vector<const CXXMethodDecl *>;
Methods->push_back(MD);
getASTContext().addOverriddenMethod(this, MD);
}
CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const {
if (!OverriddenMethods)
return 0;
OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this);
if (it == OverriddenMethods->end() || it->second->empty())
return 0;
return &(*it->second)[0];
return getASTContext().overridden_methods_begin(this);
}
CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const {
if (!OverriddenMethods)
return 0;
OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this);
if (it == OverriddenMethods->end() || it->second->empty())
return 0;
return &(*it->second)[0] + it->second->size();
return getASTContext().overridden_methods_end(this);
}
QualType CXXMethodDecl::getThisType(ASTContext &C) const {

View File

@ -202,6 +202,17 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
setProtocolList(ProtocolRefs.data(), NumProtoRefs, ProtocolLocs.data(), C);
}
/// getClassExtension - Find class extension of the given class.
// FIXME. can speed it up, if need be.
ObjCCategoryDecl* ObjCInterfaceDecl::getClassExtension() const {
const ObjCInterfaceDecl* ClassDecl = this;
for (ObjCCategoryDecl *CDecl = ClassDecl->getCategoryList(); CDecl;
CDecl = CDecl->getNextClassCategory())
if (CDecl->IsClassExtension())
return CDecl;
return 0;
}
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
ObjCInterfaceDecl* ClassDecl = this;
@ -210,6 +221,12 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
clsDeclared = ClassDecl;
return I;
}
if (const ObjCCategoryDecl *CDecl = ClassDecl->getClassExtension())
if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) {
clsDeclared = ClassDecl;
return I;
}
ClassDecl = ClassDecl->getSuperClass();
}
return NULL;

View File

@ -1120,8 +1120,15 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
break;
case ImplicitCastExprClass:
return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid
: LV_InvalidExpression;
if (cast<ImplicitCastExpr>(this)->isLvalueCast())
return LV_Valid;
// If this is a conversion to a class temporary, make a note of
// that.
if (Ctx.getLangOptions().CPlusPlus && getType()->isRecordType())
return LV_ClassTemporary;
break;
case ParenExprClass: // C99 6.5.1p5
return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx);
case BinaryOperatorClass:
@ -1171,9 +1178,15 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (ReturnType->isLValueReferenceType())
return LV_Valid;
// If the function is returning a class temporary, make a note of
// that.
if (Ctx.getLangOptions().CPlusPlus && ReturnType->isRecordType())
return LV_ClassTemporary;
break;
}
case CompoundLiteralExprClass: // C99 6.5.2.5p5
// FIXME: Is this what we want in C++?
return LV_Valid;
case ChooseExprClass:
// __builtin_choose_expr is an lvalue if the selected operand is.
@ -1207,6 +1220,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (cast<ExplicitCastExpr>(this)->getTypeAsWritten()->
isLValueReferenceType())
return LV_Valid;
// If this is a conversion to a class temporary, make a note of
// that.
if (Ctx.getLangOptions().CPlusPlus &&
cast<ExplicitCastExpr>(this)->getTypeAsWritten()->isRecordType())
return LV_ClassTemporary;
break;
case CXXTypeidExprClass:
// C++ 5.2.8p1: The result of a typeid expression is an lvalue of ...
@ -1253,6 +1273,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
break;
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXZeroInitValueExprClass:
return LV_ClassTemporary;
default:
break;
}
@ -1296,6 +1321,8 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
case LV_SubObjCPropertyGetterSetting:
return MLV_SubObjCPropertyGetterSetting;
case LV_ClassTemporary:
return MLV_ClassTemporary;
}
// The following is illegal:
@ -1655,11 +1682,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
return NoDiag();
if (Ctx.getLangOptions().CPlusPlus &&
E->getType().getCVRQualifiers() == Qualifiers::Const) {
const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
// Parameter variables are never constants. Without this check,
// getAnyInitializer() can find a default argument, which leads
// to chaos.
if (isa<ParmVarDecl>(D))
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
// C++ 7.1.5.1p2
// A variable of non-volatile const-qualified integral or enumeration
// type initialized by an ICE can be used in ICEs.
if (const VarDecl *Dcl =
dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) {
Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers();
if (Quals.hasVolatile() || !Quals.hasConst())
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());

View File

@ -15,6 +15,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@ -121,6 +122,27 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
return &Base + 1;
}
PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
: Type(Info)
{
Location = Info->getTypeLoc().getSourceRange().getBegin();
}
QualType CXXPseudoDestructorExpr::getDestroyedType() const {
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
return TInfo->getType();
return QualType();
}
SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
SourceLocation End = DestroyedType.getLocation();
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
End = TInfo->getTypeLoc().getSourceRange().getEnd();
return SourceRange(Base->getLocStart(), End);
}
// UnresolvedLookupExpr
UnresolvedLookupExpr *
UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,

View File

@ -1560,6 +1560,31 @@ static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
}
static bool TryEvaluateBuiltinNaN(ASTContext &Context,
QualType ResultTy,
const Expr *Arg,
bool SNaN,
llvm::APFloat &Result) {
const StringLiteral *S = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
if (!S) return false;
const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(ResultTy);
llvm::APInt fill;
// Treat empty strings as if they were zero.
if (S->getString().empty())
fill = llvm::APInt(32, 0);
else if (S->getString().getAsInteger(0, fill))
return false;
if (SNaN)
Result = llvm::APFloat::getSNaN(Sem, false, &fill);
else
Result = llvm::APFloat::getQNaN(Sem, false, &fill);
return true;
}
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->isBuiltinCall(Info.Ctx)) {
default: return false;
@ -1575,24 +1600,19 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
return true;
}
case Builtin::BI__builtin_nans:
case Builtin::BI__builtin_nansf:
case Builtin::BI__builtin_nansl:
return TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
true, Result);
case Builtin::BI__builtin_nan:
case Builtin::BI__builtin_nanf:
case Builtin::BI__builtin_nanl:
// If this is __builtin_nan() turn this into a nan, otherwise we
// can't constant fold it.
if (const StringLiteral *S =
dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts())) {
if (!S->isWide()) {
const llvm::fltSemantics &Sem =
Info.Ctx.getFloatTypeSemantics(E->getType());
unsigned Type = 0;
if (!S->getString().empty() && S->getString().getAsInteger(0, Type))
return false;
Result = llvm::APFloat::getNaN(Sem, false, Type);
return true;
}
}
return false;
return TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
false, Result);
case Builtin::BI__builtin_fabs:
case Builtin::BI__builtin_fabsf:

View File

@ -487,6 +487,7 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
FinishLayout();
}
// FIXME. Impl is no longer needed.
void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl) {
if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
@ -508,10 +509,9 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
UpdateAlignment(AA->getMaxAlignment());
// Layout each ivar sequentially.
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
Ctx.ShallowCollectObjCIvars(D, Ivars, Impl);
Ctx.ShallowCollectObjCIvars(D, Ivars);
for (unsigned i = 0, e = Ivars.size(); i != e; ++i)
LayoutField(Ivars[i]);

View File

@ -1120,7 +1120,10 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
E->getQualifier()->print(OS, Policy);
std::string TypeS;
E->getDestroyedType().getAsStringInternal(TypeS, Policy);
if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
OS << II->getName();
else
E->getDestroyedType().getAsStringInternal(TypeS, Policy);
OS << TypeS;
}

View File

@ -186,6 +186,18 @@ LocationContext::getStackFrameForDeclContext(const DeclContext *DC) const {
return NULL;
}
bool LocationContext::isParentOf(const LocationContext *LC) const {
do {
const LocationContext *Parent = LC->getParent();
if (Parent == this)
return true;
else
LC = Parent;
} while (LC);
return false;
}
//===----------------------------------------------------------------------===//
// Lazily generated map to query the external variables referenced by a Block.
//===----------------------------------------------------------------------===//

View File

@ -38,11 +38,16 @@ static SourceLocation GetEndLoc(Decl* D) {
class AddStmtChoice {
public:
enum Kind { NotAlwaysAdd = 0, AlwaysAdd, AlwaysAddAsLValue };
public:
AddStmtChoice(Kind kind) : k(kind) {}
bool alwaysAdd() const { return k != NotAlwaysAdd; }
bool asLValue() const { return k == AlwaysAddAsLValue; }
enum Kind { NotAlwaysAdd = 0,
AlwaysAdd = 1,
AsLValueNotAlwaysAdd = 2,
AlwaysAddAsLValue = 3 };
AddStmtChoice(Kind kind) : k(kind) {}
bool alwaysAdd() const { return (unsigned)k & 0x1; }
bool asLValue() const { return k >= AlwaysAddAsLValue; }
private:
Kind k;
};
@ -589,7 +594,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
AddEHEdge = false;
if (!NoReturn && !AddEHEdge)
return VisitStmt(C, asc);
return VisitStmt(C, AddStmtChoice::AlwaysAdd);
if (Block) {
Succ = Block;
@ -771,18 +776,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(Decl* D) {
Expr *Init = VD->getInit();
if (Init) {
// Optimization: Don't create separate block-level statements for literals.
switch (Init->getStmtClass()) {
case Stmt::IntegerLiteralClass:
case Stmt::CharacterLiteralClass:
case Stmt::StringLiteralClass:
break;
default:
Block = addStmt(Init,
VD->getType()->isReferenceType()
? AddStmtChoice::AlwaysAddAsLValue
: AddStmtChoice::AlwaysAdd);
}
AddStmtChoice::Kind k =
VD->getType()->isReferenceType() ? AddStmtChoice::AsLValueNotAlwaysAdd
: AddStmtChoice::NotAlwaysAdd;
Visit(Init, AddStmtChoice(k));
}
// If the type of VD is a VLA, then we must process its size expressions.

View File

@ -5,6 +5,7 @@ add_clang_library(clangAnalysis
CFG.cpp
LiveVariables.cpp
PrintfFormatString.cpp
ReachableCode.cpp
UninitializedValues.cpp
)

View File

@ -86,6 +86,12 @@ LiveVariables::LiveVariables(AnalysisContext &AC) {
RegisterDecls R(getAnalysisData());
cfg.VisitBlockStmts(R);
// Register all parameters even if they didn't occur in the function body.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(AC.getDecl()))
for (FunctionDecl::param_const_iterator PI = FD->param_begin(),
PE = FD->param_end(); PI != PE; ++PI)
getAnalysisData().Register(*PI);
}
//===----------------------------------------------------------------------===//
@ -274,9 +280,16 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end();
DI != DE; ++DI)
if (VarDecl* VD = dyn_cast<VarDecl>(*DI)) {
// The initializer is evaluated after the variable comes into scope.
// Update liveness information by killing the VarDecl.
unsigned bit = AD.getIdx(VD);
LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
// The initializer is evaluated after the variable comes into scope, but
// before the DeclStmt (which binds the value to the variable).
// Since this is a reverse dataflow analysis, we must evaluate the
// transfer function for this expression first.
// transfer function for this expression after the DeclStmt. If the
// initializer references the variable (which is bad) then we extend
// its liveness.
if (Expr* Init = VD->getInit())
Visit(Init);
@ -286,10 +299,6 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
StmtIterator E;
for (; I != E; ++I) Visit(*I);
}
// Update liveness information by killing the VarDecl.
unsigned bit = AD.getIdx(VD);
LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
}
}

View File

@ -15,10 +15,12 @@
#include "clang/Analysis/Analyses/PrintfFormatString.h"
#include "clang/AST/ASTContext.h"
using clang::analyze_printf::FormatSpecifier;
using clang::analyze_printf::OptionalAmount;
using clang::analyze_printf::ArgTypeResult;
using clang::analyze_printf::FormatSpecifier;
using clang::analyze_printf::FormatStringHandler;
using clang::analyze_printf::OptionalAmount;
using clang::analyze_printf::PositionContext;
using namespace clang;
namespace {
@ -66,24 +68,19 @@ static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
const char *I = Beg;
UpdateOnReturn <const char*> UpdateBeg(Beg, I);
bool foundDigits = false;
unsigned accumulator = 0;
bool hasDigits = false;
for ( ; I != E; ++I) {
char c = *I;
if (c >= '0' && c <= '9') {
foundDigits = true;
hasDigits = true;
accumulator += (accumulator * 10) + (c - '0');
continue;
}
if (foundDigits)
return OptionalAmount(accumulator, Beg);
if (c == '*') {
++I;
return OptionalAmount(OptionalAmount::Arg, Beg);
}
if (hasDigits)
return OptionalAmount(OptionalAmount::Constant, accumulator, Beg);
break;
}
@ -91,9 +88,129 @@ static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
return OptionalAmount();
}
static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
unsigned &argIndex) {
if (*Beg == '*') {
++Beg;
return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg);
}
return ParseAmount(Beg, E);
}
static OptionalAmount ParsePositionAmount(FormatStringHandler &H,
const char *Start,
const char *&Beg, const char *E,
PositionContext p) {
if (*Beg == '*') {
const char *I = Beg + 1;
const OptionalAmount &Amt = ParseAmount(I, E);
if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
H.HandleInvalidPosition(Beg, I - Beg, p);
return OptionalAmount(false);
}
if (I== E) {
// No more characters left?
H.HandleIncompleteFormatSpecifier(Start, E - Start);
return OptionalAmount(false);
}
assert(Amt.getHowSpecified() == OptionalAmount::Constant);
if (*I == '$') {
// Special case: '*0$', since this is an easy mistake.
if (Amt.getConstantAmount() == 0) {
H.HandleZeroPosition(Beg, I - Beg + 1);
return OptionalAmount(false);
}
const char *Tmp = Beg;
Beg = ++I;
return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
Tmp);
}
H.HandleInvalidPosition(Beg, I - Beg, p);
return OptionalAmount(false);
}
return ParseAmount(Beg, E);
}
static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS,
const char *Start, const char *&Beg, const char *E,
unsigned *argIndex) {
if (argIndex) {
FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
}
else {
const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
analyze_printf::PrecisionPos);
if (Amt.isInvalid())
return true;
FS.setPrecision(Amt);
}
return false;
}
static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS,
const char *Start, const char *&Beg, const char *E,
unsigned *argIndex) {
// FIXME: Support negative field widths.
if (argIndex) {
FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
}
else {
const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
analyze_printf::FieldWidthPos);
if (Amt.isInvalid())
return true;
FS.setFieldWidth(Amt);
}
return false;
}
static bool ParseArgPosition(FormatStringHandler &H,
FormatSpecifier &FS, const char *Start,
const char *&Beg, const char *E) {
using namespace clang::analyze_printf;
const char *I = Beg;
const OptionalAmount &Amt = ParseAmount(I, E);
if (I == E) {
// No more characters left?
H.HandleIncompleteFormatSpecifier(Start, E - Start);
return true;
}
if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
// Special case: '%0$', since this is an easy mistake.
if (Amt.getConstantAmount() == 0) {
H.HandleZeroPosition(Start, I - Start);
return true;
}
FS.setArgIndex(Amt.getConstantAmount() - 1);
FS.setUsesPositionalArg();
// Update the caller's pointer if we decided to consume
// these characters.
Beg = I;
return false;
}
return false;
}
static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E) {
const char *E,
unsigned &argIndex) {
using namespace clang::analyze_printf;
@ -126,6 +243,14 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
}
FormatSpecifier FS;
if (ParseArgPosition(H, FS, Start, I, E))
return true;
if (I == E) {
// No more characters left?
H.HandleIncompleteFormatSpecifier(Start, E - Start);
return true;
}
// Look for flags (if any).
bool hasMore = true;
@ -149,7 +274,9 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
}
// Look for the field width (if any).
FS.setFieldWidth(ParseAmount(I, E));
if (ParseFieldWidth(H, FS, Start, I, E,
FS.usesPositionalArg() ? 0 : &argIndex))
return true;
if (I == E) {
// No more characters left?
@ -165,7 +292,9 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
return true;
}
FS.setPrecision(ParseAmount(I, E));
if (ParsePrecision(H, FS, Start, I, E,
FS.usesPositionalArg() ? 0 : &argIndex))
return true;
if (I == E) {
// No more characters left?
@ -214,44 +343,53 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
default:
break;
// C99: 7.19.6.1 (section 8).
case '%': k = ConversionSpecifier::PercentArg; break;
case 'A': k = ConversionSpecifier::AArg; break;
case 'E': k = ConversionSpecifier::EArg; break;
case 'F': k = ConversionSpecifier::FArg; break;
case 'G': k = ConversionSpecifier::GArg; break;
case 'X': k = ConversionSpecifier::XArg; break;
case 'a': k = ConversionSpecifier::aArg; break;
case 'c': k = ConversionSpecifier::IntAsCharArg; break;
case 'd': k = ConversionSpecifier::dArg; break;
case 'e': k = ConversionSpecifier::eArg; break;
case 'f': k = ConversionSpecifier::fArg; break;
case 'g': k = ConversionSpecifier::gArg; break;
case 'i': k = ConversionSpecifier::iArg; break;
case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
case 'o': k = ConversionSpecifier::oArg; break;
case 'p': k = ConversionSpecifier::VoidPtrArg; break;
case 's': k = ConversionSpecifier::CStrArg; break;
case 'u': k = ConversionSpecifier::uArg; break;
case 'x': k = ConversionSpecifier::xArg; break;
case 'X': k = ConversionSpecifier::XArg; break;
case 'f': k = ConversionSpecifier::fArg; break;
case 'F': k = ConversionSpecifier::FArg; break;
case 'e': k = ConversionSpecifier::eArg; break;
case 'E': k = ConversionSpecifier::EArg; break;
case 'g': k = ConversionSpecifier::gArg; break;
case 'G': k = ConversionSpecifier::GArg; break;
case 'a': k = ConversionSpecifier::aArg; break;
case 'A': k = ConversionSpecifier::AArg; break;
case 'c': k = ConversionSpecifier::IntAsCharArg; break;
case 's': k = ConversionSpecifier::CStrArg; break;
case 'p': k = ConversionSpecifier::VoidPtrArg; break;
case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
case '%': k = ConversionSpecifier::PercentArg; break;
// Mac OS X (unicode) specific
case 'C': k = ConversionSpecifier::CArg; break;
case 'S': k = ConversionSpecifier::UnicodeStrArg; break;
// Objective-C.
case '@': k = ConversionSpecifier::ObjCObjArg; break;
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
}
FS.setConversionSpecifier(ConversionSpecifier(conversionPosition, k));
ConversionSpecifier CS(conversionPosition, k);
FS.setConversionSpecifier(CS);
if (CS.consumesDataArgument() && !FS.usesPositionalArg())
FS.setArgIndex(argIndex++);
if (k == ConversionSpecifier::InvalidSpecifier) {
H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
return false; // Keep processing format specifiers.
// Assume the conversion takes one argument.
return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
}
return FormatSpecifierResult(Start, FS);
}
bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
const char *I, const char *E) {
unsigned argIndex = 0;
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E);
const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
@ -345,8 +483,10 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
if (!PT)
return false;
QualType pointeeTy = PT->getPointeeType();
return pointeeTy == C.WCharTy;
QualType pointeeTy =
C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
return pointeeTy == C.getWCharType();
}
return false;
@ -359,7 +499,7 @@ QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
if (K == CStrTy)
return C.getPointerType(C.CharTy);
if (K == WCStrTy)
return C.getPointerType(C.WCharTy);
return C.getPointerType(C.getWCharType());
if (K == ObjCPointerTy)
return C.ObjCBuiltinIdTy;
@ -426,9 +566,17 @@ ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
return Ctx.DoubleTy;
}
if (CS.getKind() == ConversionSpecifier::CStrArg)
return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy
: ArgTypeResult::CStrTy);
switch (CS.getKind()) {
case ConversionSpecifier::CStrArg:
return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
case ConversionSpecifier::UnicodeStrArg:
// FIXME: This appears to be Mac OS X specific.
return ArgTypeResult::WCStrTy;
case ConversionSpecifier::CArg:
return Ctx.WCharTy;
default:
break;
}
// FIXME: Handle other cases.
return ArgTypeResult();

View File

@ -0,0 +1,278 @@
//=- ReachableCodePathInsensitive.cpp ---------------------------*- 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 a flow-sensitive, path-insensitive analysis of
// determining reachable blocks within a CFG.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/SourceManager.h"
using namespace clang;
static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
SourceRange &R2) {
const Stmt *S = 0;
unsigned sn = 0;
R1 = R2 = SourceRange();
top:
if (sn < b.size())
S = b[sn].getStmt();
else if (b.getTerminator())
S = b.getTerminator();
else
return SourceLocation();
switch (S->getStmtClass()) {
case Expr::BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(S);
if (BO->getOpcode() == BinaryOperator::Comma) {
if (sn+1 < b.size())
return b[sn+1].getStmt()->getLocStart();
const CFGBlock *n = &b;
while (1) {
if (n->getTerminator())
return n->getTerminator()->getLocStart();
if (n->succ_size() != 1)
return SourceLocation();
n = n[0].succ_begin()[0];
if (n->pred_size() != 1)
return SourceLocation();
if (!n->empty())
return n[0][0].getStmt()->getLocStart();
}
}
R1 = BO->getLHS()->getSourceRange();
R2 = BO->getRHS()->getSourceRange();
return BO->getOperatorLoc();
}
case Expr::UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(S);
R1 = UO->getSubExpr()->getSourceRange();
return UO->getOperatorLoc();
}
case Expr::CompoundAssignOperatorClass: {
const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
R1 = CAO->getLHS()->getSourceRange();
R2 = CAO->getRHS()->getSourceRange();
return CAO->getOperatorLoc();
}
case Expr::ConditionalOperatorClass: {
const ConditionalOperator *CO = cast<ConditionalOperator>(S);
return CO->getQuestionLoc();
}
case Expr::MemberExprClass: {
const MemberExpr *ME = cast<MemberExpr>(S);
R1 = ME->getSourceRange();
return ME->getMemberLoc();
}
case Expr::ArraySubscriptExprClass: {
const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
R1 = ASE->getLHS()->getSourceRange();
R2 = ASE->getRHS()->getSourceRange();
return ASE->getRBracketLoc();
}
case Expr::CStyleCastExprClass: {
const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
R1 = CSC->getSubExpr()->getSourceRange();
return CSC->getLParenLoc();
}
case Expr::CXXFunctionalCastExprClass: {
const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
R1 = CE->getSubExpr()->getSourceRange();
return CE->getTypeBeginLoc();
}
case Expr::ImplicitCastExprClass:
++sn;
goto top;
case Stmt::CXXTryStmtClass: {
return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
}
default: ;
}
R1 = S->getSourceRange();
return S->getLocStart();
}
static SourceLocation MarkLiveTop(const CFGBlock *Start,
llvm::BitVector &reachable,
SourceManager &SM) {
// Prep work worklist.
llvm::SmallVector<const CFGBlock*, 32> WL;
WL.push_back(Start);
SourceRange R1, R2;
SourceLocation top = GetUnreachableLoc(*Start, R1, R2);
bool FromMainFile = false;
bool FromSystemHeader = false;
bool TopValid = false;
if (top.isValid()) {
FromMainFile = SM.isFromMainFile(top);
FromSystemHeader = SM.isInSystemHeader(top);
TopValid = true;
}
// Solve
while (!WL.empty()) {
const CFGBlock *item = WL.back();
WL.pop_back();
SourceLocation c = GetUnreachableLoc(*item, R1, R2);
if (c.isValid()
&& (!TopValid
|| (SM.isFromMainFile(c) && !FromMainFile)
|| (FromSystemHeader && !SM.isInSystemHeader(c))
|| SM.isBeforeInTranslationUnit(c, top))) {
top = c;
FromMainFile = SM.isFromMainFile(top);
FromSystemHeader = SM.isInSystemHeader(top);
}
reachable.set(item->getBlockID());
for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end();
I != E; ++I)
if (const CFGBlock *B = *I) {
unsigned blockID = B->getBlockID();
if (!reachable[blockID]) {
reachable.set(blockID);
WL.push_back(B);
}
}
}
return top;
}
static int LineCmp(const void *p1, const void *p2) {
SourceLocation *Line1 = (SourceLocation *)p1;
SourceLocation *Line2 = (SourceLocation *)p2;
return !(*Line1 < *Line2);
}
namespace {
struct ErrLoc {
SourceLocation Loc;
SourceRange R1;
SourceRange R2;
ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2)
: Loc(l), R1(r1), R2(r2) { }
};
}
namespace clang { namespace reachable_code {
/// ScanReachableFromBlock - Mark all blocks reachable from Start.
/// Returns the total number of blocks that were marked reachable.
unsigned ScanReachableFromBlock(const CFGBlock &Start,
llvm::BitVector &Reachable) {
unsigned count = 0;
llvm::SmallVector<const CFGBlock*, 32> WL;
// Prep work queue
Reachable.set(Start.getBlockID());
++count;
WL.push_back(&Start);
// Find the reachable blocks from 'Start'.
while (!WL.empty()) {
const CFGBlock *item = WL.back();
WL.pop_back();
// Look at the successors and mark then reachable.
for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end();
I != E; ++I)
if (const CFGBlock *B = *I) {
unsigned blockID = B->getBlockID();
if (!Reachable[blockID]) {
Reachable.set(blockID);
++count;
WL.push_back(B);
}
}
}
return count;
}
void FindUnreachableCode(AnalysisContext &AC, Callback &CB) {
CFG *cfg = AC.getCFG();
if (!cfg)
return;
// Scan for reachable blocks.
llvm::BitVector reachable(cfg->getNumBlockIDs());
unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable);
// If there are no unreachable blocks, we're done.
if (numReachable == cfg->getNumBlockIDs())
return;
SourceRange R1, R2;
llvm::SmallVector<ErrLoc, 24> lines;
bool AddEHEdges = AC.getAddEHEdges();
// First, give warnings for blocks with no predecessors, as they
// can't be part of a loop.
for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
CFGBlock &b = **I;
if (!reachable[b.getBlockID()]) {
if (b.pred_empty()) {
if (!AddEHEdges && dyn_cast_or_null<CXXTryStmt>(b.getTerminator())) {
// When not adding EH edges from calls, catch clauses
// can otherwise seem dead. Avoid noting them as dead.
numReachable += ScanReachableFromBlock(b, reachable);
continue;
}
SourceLocation c = GetUnreachableLoc(b, R1, R2);
if (!c.isValid()) {
// Blocks without a location can't produce a warning, so don't mark
// reachable blocks from here as live.
reachable.set(b.getBlockID());
++numReachable;
continue;
}
lines.push_back(ErrLoc(c, R1, R2));
// Avoid excessive errors by marking everything reachable from here
numReachable += ScanReachableFromBlock(b, reachable);
}
}
}
if (numReachable < cfg->getNumBlockIDs()) {
// And then give warnings for the tops of loops.
for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
CFGBlock &b = **I;
if (!reachable[b.getBlockID()])
// Avoid excessive errors by marking everything reachable from here
lines.push_back(ErrLoc(MarkLiveTop(&b, reachable,
AC.getASTContext().getSourceManager()),
SourceRange(), SourceRange()));
}
}
llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
for (llvm::SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end();
I != E; ++I)
if (I->Loc.isValid())
CB.HandleUnreachable(I->Loc, I->R1, I->R2);
}
}} // end namespace clang::reachable_code

View File

@ -134,8 +134,12 @@ bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) {
VarDecl *VD = dyn_cast<VarDecl>(*I);
if (VD && VD->isBlockVarDecl()) {
if (Stmt* I = VD->getInit())
V(VD,AD) = AD.FullUninitTaint ? V(cast<Expr>(I),AD) : Initialized;
if (Stmt* I = VD->getInit()) {
// Visit the subexpression to check for uses of uninitialized values,
// even if we don't propagate that value.
bool isSubExprUninit = Visit(I);
V(VD,AD) = AD.FullUninitTaint ? isSubExprUninit : Initialized;
}
else {
// Special case for declarations of array types. For things like:
//

View File

@ -387,123 +387,6 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
return Result;
}
static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
unsigned &Value) {
if (Memory + sizeof(unsigned) > MemoryEnd)
return true;
memmove(&Value, Memory, sizeof(unsigned));
Memory += sizeof(unsigned);
return false;
}
static bool ReadSourceLocation(FileManager &FM, SourceManager &SM,
const char *&Memory, const char *MemoryEnd,
SourceLocation &Location) {
// Read the filename.
unsigned FileNameLen = 0;
if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) ||
Memory + FileNameLen > MemoryEnd)
return true;
llvm::StringRef FileName(Memory, FileNameLen);
Memory += FileNameLen;
// Read the line, column.
unsigned Line = 0, Column = 0;
if (ReadUnsigned(Memory, MemoryEnd, Line) ||
ReadUnsigned(Memory, MemoryEnd, Column))
return true;
if (FileName.empty()) {
Location = SourceLocation();
return false;
}
const FileEntry *File = FM.getFile(FileName);
if (!File)
return true;
// Make sure that this file has an entry in the source manager.
if (!SM.hasFileInfo(File))
SM.createFileID(File, SourceLocation(), SrcMgr::C_User);
Location = SM.getLocation(File, Line, Column);
return false;
}
DiagnosticBuilder Diagnostic::Deserialize(FileManager &FM, SourceManager &SM,
const char *&Memory,
const char *MemoryEnd) {
if (Memory == MemoryEnd)
return DiagnosticBuilder(0);
// Read the severity level.
unsigned Level = 0;
if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Fatal)
return DiagnosticBuilder(0);
// Read the source location.
SourceLocation Location;
if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location))
return DiagnosticBuilder(0);
// Read the diagnostic text.
if (Memory == MemoryEnd)
return DiagnosticBuilder(0);
unsigned MessageLen = 0;
if (ReadUnsigned(Memory, MemoryEnd, MessageLen) ||
Memory + MessageLen > MemoryEnd)
return DiagnosticBuilder(0);
llvm::StringRef Message(Memory, MessageLen);
Memory += MessageLen;
// At this point, we have enough information to form a diagnostic. Do so.
unsigned DiagID = getCustomDiagID((enum Level)Level, Message);
DiagnosticBuilder DB = Report(FullSourceLoc(Location, SM), DiagID);
if (Memory == MemoryEnd)
return DB;
// Read the source ranges.
unsigned NumSourceRanges = 0;
if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges))
return DB;
for (unsigned I = 0; I != NumSourceRanges; ++I) {
SourceLocation Begin, End;
if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) ||
ReadSourceLocation(FM, SM, Memory, MemoryEnd, End))
return DB;
DB << SourceRange(Begin, End);
}
// Read the fix-it hints.
unsigned NumFixIts = 0;
if (ReadUnsigned(Memory, MemoryEnd, NumFixIts))
return DB;
for (unsigned I = 0; I != NumFixIts; ++I) {
SourceLocation RemoveBegin, RemoveEnd, InsertionLoc;
unsigned InsertLen = 0;
if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) ||
ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) ||
ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) ||
ReadUnsigned(Memory, MemoryEnd, InsertLen) ||
Memory + InsertLen > MemoryEnd)
return DB;
CodeModificationHint Hint;
Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd);
Hint.InsertionLoc = InsertionLoc;
Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
Memory += InsertLen;
DB << Hint;
}
return DB;
}
struct WarningOption {
const char *Name;
const short *Members;
@ -1036,6 +919,31 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
}
}
StoredDiagnostic::StoredDiagnostic() { }
StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
llvm::StringRef Message)
: Level(Level), Loc(), Message(Message) { }
StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
const DiagnosticInfo &Info)
: Level(Level), Loc(Info.getLocation())
{
llvm::SmallString<64> Message;
Info.FormatDiagnostic(Message);
this->Message.assign(Message.begin(), Message.end());
Ranges.reserve(Info.getNumRanges());
for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I)
Ranges.push_back(Info.getRange(I));
FixIts.reserve(Info.getNumCodeModificationHints());
for (unsigned I = 0, N = Info.getNumCodeModificationHints(); I != N; ++I)
FixIts.push_back(Info.getCodeModificationHint(I));
}
StoredDiagnostic::~StoredDiagnostic() { }
static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
OS.write((const char *)&Value, sizeof(unsigned));
}
@ -1065,27 +973,27 @@ static void WriteSourceLocation(llvm::raw_ostream &OS,
WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second));
}
void DiagnosticInfo::Serialize(Diagnostic::Level DiagLevel,
llvm::raw_ostream &OS) const {
void StoredDiagnostic::Serialize(llvm::raw_ostream &OS) const {
SourceManager *SM = 0;
if (getLocation().isValid())
SM = &const_cast<SourceManager &>(getLocation().getManager());
// Write a short header to help identify diagnostics.
OS << (char)0x06 << (char)0x07;
// Write the diagnostic level and location.
WriteUnsigned(OS, (unsigned)DiagLevel);
WriteUnsigned(OS, (unsigned)Level);
WriteSourceLocation(OS, SM, getLocation());
// Write the diagnostic message.
llvm::SmallString<64> Message;
FormatDiagnostic(Message);
WriteString(OS, Message);
WriteString(OS, getMessage());
// Count the number of ranges that don't point into macros, since
// only simple file ranges serialize well.
unsigned NumNonMacroRanges = 0;
for (unsigned I = 0, N = getNumRanges(); I != N; ++I) {
SourceRange R = getRange(I);
if (R.getBegin().isMacroID() || R.getEnd().isMacroID())
for (range_iterator R = range_begin(), REnd = range_end(); R != REnd; ++R) {
if (R->getBegin().isMacroID() || R->getEnd().isMacroID())
continue;
++NumNonMacroRanges;
@ -1094,46 +1002,187 @@ void DiagnosticInfo::Serialize(Diagnostic::Level DiagLevel,
// Write the ranges.
WriteUnsigned(OS, NumNonMacroRanges);
if (NumNonMacroRanges) {
for (unsigned I = 0, N = getNumRanges(); I != N; ++I) {
SourceRange R = getRange(I);
if (R.getBegin().isMacroID() || R.getEnd().isMacroID())
for (range_iterator R = range_begin(), REnd = range_end(); R != REnd; ++R) {
if (R->getBegin().isMacroID() || R->getEnd().isMacroID())
continue;
WriteSourceLocation(OS, SM, R.getBegin());
WriteSourceLocation(OS, SM, R.getEnd());
WriteSourceLocation(OS, SM, R->getBegin());
WriteSourceLocation(OS, SM, R->getEnd());
}
}
// Determine if all of the fix-its involve rewrites with simple file
// locations (not in macro instantiations). If so, we can write
// fix-it information.
unsigned NumFixIts = getNumCodeModificationHints();
for (unsigned I = 0; I != NumFixIts; ++I) {
const CodeModificationHint &Hint = getCodeModificationHint(I);
if (Hint.RemoveRange.isValid() &&
(Hint.RemoveRange.getBegin().isMacroID() ||
Hint.RemoveRange.getEnd().isMacroID())) {
unsigned NumFixIts = 0;
for (fixit_iterator F = fixit_begin(), FEnd = fixit_end(); F != FEnd; ++F) {
if (F->RemoveRange.isValid() &&
(F->RemoveRange.getBegin().isMacroID() ||
F->RemoveRange.getEnd().isMacroID())) {
NumFixIts = 0;
break;
}
if (Hint.InsertionLoc.isValid() && Hint.InsertionLoc.isMacroID()) {
if (F->InsertionLoc.isValid() && F->InsertionLoc.isMacroID()) {
NumFixIts = 0;
break;
}
++NumFixIts;
}
// Write the fix-its.
WriteUnsigned(OS, NumFixIts);
for (unsigned I = 0; I != NumFixIts; ++I) {
const CodeModificationHint &Hint = getCodeModificationHint(I);
WriteSourceLocation(OS, SM, Hint.RemoveRange.getBegin());
WriteSourceLocation(OS, SM, Hint.RemoveRange.getEnd());
WriteSourceLocation(OS, SM, Hint.InsertionLoc);
WriteString(OS, Hint.CodeToInsert);
for (fixit_iterator F = fixit_begin(), FEnd = fixit_end(); F != FEnd; ++F) {
WriteSourceLocation(OS, SM, F->RemoveRange.getBegin());
WriteSourceLocation(OS, SM, F->RemoveRange.getEnd());
WriteSourceLocation(OS, SM, F->InsertionLoc);
WriteString(OS, F->CodeToInsert);
}
}
static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
unsigned &Value) {
if (Memory + sizeof(unsigned) > MemoryEnd)
return true;
memmove(&Value, Memory, sizeof(unsigned));
Memory += sizeof(unsigned);
return false;
}
static bool ReadSourceLocation(FileManager &FM, SourceManager &SM,
const char *&Memory, const char *MemoryEnd,
SourceLocation &Location) {
// Read the filename.
unsigned FileNameLen = 0;
if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) ||
Memory + FileNameLen > MemoryEnd)
return true;
llvm::StringRef FileName(Memory, FileNameLen);
Memory += FileNameLen;
// Read the line, column.
unsigned Line = 0, Column = 0;
if (ReadUnsigned(Memory, MemoryEnd, Line) ||
ReadUnsigned(Memory, MemoryEnd, Column))
return true;
if (FileName.empty()) {
Location = SourceLocation();
return false;
}
const FileEntry *File = FM.getFile(FileName);
if (!File)
return true;
// Make sure that this file has an entry in the source manager.
if (!SM.hasFileInfo(File))
SM.createFileID(File, SourceLocation(), SrcMgr::C_User);
Location = SM.getLocation(File, Line, Column);
return false;
}
StoredDiagnostic
StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM,
const char *&Memory, const char *MemoryEnd) {
while (true) {
if (Memory == MemoryEnd)
return StoredDiagnostic();
if (*Memory != 0x06) {
++Memory;
continue;
}
++Memory;
if (Memory == MemoryEnd)
return StoredDiagnostic();
if (*Memory != 0x07) {
++Memory;
continue;
}
// We found the header. We're done.
++Memory;
break;
}
// Read the severity level.
unsigned Level = 0;
if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Diagnostic::Fatal)
return StoredDiagnostic();
// Read the source location.
SourceLocation Location;
if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location))
return StoredDiagnostic();
// Read the diagnostic text.
if (Memory == MemoryEnd)
return StoredDiagnostic();
unsigned MessageLen = 0;
if (ReadUnsigned(Memory, MemoryEnd, MessageLen) ||
Memory + MessageLen > MemoryEnd)
return StoredDiagnostic();
llvm::StringRef Message(Memory, MessageLen);
Memory += MessageLen;
// At this point, we have enough information to form a diagnostic. Do so.
StoredDiagnostic Diag;
Diag.Level = (Diagnostic::Level)Level;
Diag.Loc = FullSourceLoc(Location, SM);
Diag.Message = Message;
if (Memory == MemoryEnd)
return Diag;
// Read the source ranges.
unsigned NumSourceRanges = 0;
if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges))
return Diag;
for (unsigned I = 0; I != NumSourceRanges; ++I) {
SourceLocation Begin, End;
if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) ||
ReadSourceLocation(FM, SM, Memory, MemoryEnd, End))
return Diag;
Diag.Ranges.push_back(SourceRange(Begin, End));
}
// Read the fix-it hints.
unsigned NumFixIts = 0;
if (ReadUnsigned(Memory, MemoryEnd, NumFixIts))
return Diag;
for (unsigned I = 0; I != NumFixIts; ++I) {
SourceLocation RemoveBegin, RemoveEnd, InsertionLoc;
unsigned InsertLen = 0;
if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) ||
ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) ||
ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) ||
ReadUnsigned(Memory, MemoryEnd, InsertLen) ||
Memory + InsertLen > MemoryEnd) {
Diag.FixIts.clear();
return Diag;
}
CodeModificationHint Hint;
Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd);
Hint.InsertionLoc = InsertionLoc;
Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
Memory += InsertLen;
Diag.FixIts.push_back(Hint);
}
return Diag;
}
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
/// DiagnosticClient should be included in the number of diagnostics

View File

@ -980,20 +980,6 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
if (Content->SourceLineCache == 0)
ComputeLineNumbers(Content, ContentCacheAlloc);
if (Line > Content->NumLines)
return SourceLocation();
unsigned FilePos = Content->SourceLineCache[Line - 1];
const char *Buf = Content->getBuffer()->getBufferStart() + FilePos;
unsigned BufLength = Content->getBuffer()->getBufferEnd() - Buf;
unsigned i = 0;
// Check that the given column is valid.
while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r')
++i;
if (i < Col-1)
return SourceLocation();
// Find the first file ID that corresponds to the given file.
FileID FirstFID;
@ -1020,6 +1006,24 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
if (FirstFID.isInvalid())
return SourceLocation();
if (Line > Content->NumLines) {
unsigned Size = Content->getBuffer()->getBufferSize();
if (Size > 0)
--Size;
return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size);
}
unsigned FilePos = Content->SourceLineCache[Line - 1];
const char *Buf = Content->getBuffer()->getBufferStart() + FilePos;
unsigned BufLength = Content->getBuffer()->getBufferEnd() - Buf;
unsigned i = 0;
// Check that the given column is valid.
while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r')
++i;
if (i < Col-1)
return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + i);
return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1);
}

View File

@ -436,11 +436,13 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
// Target identification.
Builder.defineMacro("__ppc__");
Builder.defineMacro("_ARCH_PPC");
Builder.defineMacro("__powerpc__");
Builder.defineMacro("__POWERPC__");
if (PointerWidth == 64) {
Builder.defineMacro("_ARCH_PPC64");
Builder.defineMacro("_LP64");
Builder.defineMacro("__LP64__");
Builder.defineMacro("__powerpc64__");
Builder.defineMacro("__ppc64__");
} else {
Builder.defineMacro("__ppc__");
@ -571,9 +573,12 @@ void PPCTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
namespace {
class PPC32TargetInfo : public PPCTargetInfo {
public:
PPC32TargetInfo(const std::string& triple) : PPCTargetInfo(triple) {
PPC32TargetInfo(const std::string &triple) : PPCTargetInfo(triple) {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
if (getTriple().getOS() == llvm::Triple::FreeBSD)
this->SizeType = TargetInfo::UnsignedInt;
}
};
} // end anonymous namespace.
@ -1919,13 +1924,39 @@ namespace {
namespace {
class MipsTargetInfo : public TargetInfo {
std::string ABI, CPU;
static const TargetInfo::GCCRegAlias GCCRegAliases[];
static const char * const GCCRegNames[];
public:
MipsTargetInfo(const std::string& triple) : TargetInfo(triple) {
MipsTargetInfo(const std::string& triple) : TargetInfo(triple), ABI("o32") {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual const char *getABI() const { return ABI.c_str(); }
virtual bool setABI(const std::string &Name) {
if ((Name == "o32") || (Name == "eabi")) {
ABI = Name;
return true;
} else
return false;
}
virtual bool setCPU(const std::string &Name) {
CPU = Name;
return true;
}
void getDefaultFeatures(const std::string &CPU,
llvm::StringMap<bool> &Features) const {
Features[ABI] = true;
Features[CPU] = true;
}
virtual void getArchDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
if (ABI == "o32")
Builder.defineMacro("__mips_o32");
else if (ABI == "eabi")
Builder.defineMacro("__mips_eabi");
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
DefineStd(Builder, "mips", Opts);
@ -1933,6 +1964,7 @@ class MipsTargetInfo : public TargetInfo {
DefineStd(Builder, "MIPSEB", Opts);
Builder.defineMacro("_MIPSEB");
Builder.defineMacro("__REGISTER_PREFIX__", "");
getArchDefines(Opts, Builder);
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@ -2044,6 +2076,7 @@ void MipselTargetInfo::getTargetDefines(const LangOptions &Opts,
DefineStd(Builder, "MIPSEL", Opts);
Builder.defineMacro("_MIPSEL");
Builder.defineMacro("__REGISTER_PREFIX__", "");
getArchDefines(Opts, Builder);
}
} // end anonymous namespace.
@ -2096,6 +2129,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::ppc:
if (os == llvm::Triple::Darwin)
return new DarwinTargetInfo<PPCTargetInfo>(T);
else if (os == llvm::Triple::FreeBSD)
return new FreeBSDTargetInfo<PPC32TargetInfo>(T);
return new PPC32TargetInfo(T);
case llvm::Triple::ppc64:
@ -2103,6 +2138,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new DarwinTargetInfo<PPC64TargetInfo>(T);
else if (os == llvm::Triple::Lv2)
return new PS3PPUTargetInfo<PPC64TargetInfo>(T);
else if (os == llvm::Triple::FreeBSD)
return new FreeBSDTargetInfo<PPC64TargetInfo>(T);
return new PPC64TargetInfo(T);
case llvm::Triple::sparc:

View File

@ -40,15 +40,15 @@ llvm::StringRef getClangRepositoryPath() {
}
std::string getClangRevision() {
#ifndef SVN_REVISION
// Subversion was not available at build time?
return "";
#else
std::string revision;
llvm::raw_string_ostream OS(revision);
OS << strtol(SVN_REVISION, 0, 10);
return revision;
#ifdef SVN_REVISION
if (SVN_REVISION[0] != '\0') {
std::string revision;
llvm::raw_string_ostream OS(revision);
OS << strtol(SVN_REVISION, 0, 10);
return revision;
}
#endif
return "";
}
std::string getClangFullRepositoryVersion() {

View File

@ -95,6 +95,8 @@ class BasicStoreManager : public StoreManager {
const char *sep);
private:
SVal LazyRetrieve(Store store, const TypedRegion *R);
ASTContext& getContext() { return StateMgr.getContext(); }
};
@ -126,6 +128,25 @@ static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
}
}
SVal BasicStoreManager::LazyRetrieve(Store store, const TypedRegion *R) {
const VarRegion *VR = dyn_cast<VarRegion>(R);
if (!VR)
return UnknownVal();
const VarDecl *VD = VR->getDecl();
QualType T = VD->getType();
// Only handle simple types that we can symbolicate.
if (!SymbolManager::canSymbolicate(T) || !T->isScalarType())
return UnknownVal();
// Globals and parameters start with symbolic values.
// Local variables initially are undefined.
if (VR->hasGlobalsOrParametersStorage())
return ValMgr.getRegionValueSymbolVal(R);
return UndefinedVal();
}
SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
if (isa<UnknownVal>(loc))
return UnknownVal();
@ -142,11 +163,13 @@ SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
BindingsTy B = GetBindings(store);
BindingsTy::data_type *Val = B.lookup(R);
const TypedRegion *TR = cast<TypedRegion>(R);
if (!Val)
break;
if (Val)
return CastRetrievedVal(*Val, TR, T);
return CastRetrievedVal(*Val, cast<TypedRegion>(R), T);
SVal V = LazyRetrieve(store, TR);
return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T);
}
case loc::ConcreteIntKind:
@ -319,7 +342,7 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
const Expr *Base = IV->getBase()->IgnoreParenCasts();
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Base)) {
if (DR->getDecl() == SelfDecl) {
const MemRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
const ObjCIvarRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
SelfRegion);
SVal X = ValMgr.getRegionValueSymbolVal(IVR);
St = Bind(St, ValMgr.makeLoc(IVR), X);
@ -351,10 +374,10 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
if (MD->getSelfDecl() == PD) {
// FIXME: Add type constraints (when they become available) to
// SelfRegion? (i.e., it implements MD->getClassInterface()).
const MemRegion *VR = MRMgr.getVarRegion(PD, InitLoc);
const VarRegion *VR = MRMgr.getVarRegion(PD, InitLoc);
const MemRegion *SelfRegion =
ValMgr.getRegionValueSymbolVal(VR).getAsRegion();
assert(SelfRegion);
ValMgr.getRegionValueSymbolVal(VR).getAsRegion();
assert(SelfRegion);
St = Bind(St, ValMgr.makeLoc(VR), loc::MemRegionVal(SelfRegion));
// Scan the method for ivar references. While this requires an
// entire AST scan, the cost should not be high in practice.
@ -362,21 +385,8 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
}
}
}
else if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
// Only handle simple types that we can symbolicate.
if (!SymbolManager::canSymbolicate(VD->getType()))
continue;
// Initialize globals and parameters to symbolic values.
// Initialize local variables to undefined.
const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD, InitLoc);
SVal X = UndefinedVal();
if (R->hasGlobalsOrParametersStorage())
X = ValMgr.getRegionValueSymbolVal(R);
St = Bind(St, ValMgr.makeLoc(R), X);
}
}
return St;
}

View File

@ -14,7 +14,6 @@
#include "GRExprEngineInternalChecks.h"
#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;

View File

@ -12,26 +12,26 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/DomainSpecific/CocoaConventions.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/Checker/DomainSpecific/CocoaConventions.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include <stdarg.h>
using namespace clang;
@ -1222,6 +1222,12 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
else if (FD->getAttr<CFReturnsRetainedAttr>()) {
Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
}
else if (FD->getAttr<NSReturnsNotRetainedAttr>()) {
Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
}
else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
}
}
else if (RetTy->getAs<PointerType>()) {
if (FD->getAttr<CFReturnsRetainedAttr>()) {
@ -1244,6 +1250,10 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
Summ.setRetEffect(ObjCAllocRetE);
return;
}
if (MD->getAttr<NSReturnsNotRetainedAttr>()) {
Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
return;
}
isTrackedLoc = true;
}
@ -1251,8 +1261,12 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
if (!isTrackedLoc)
isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL;
if (isTrackedLoc && MD->getAttr<CFReturnsRetainedAttr>())
Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
if (isTrackedLoc) {
if (MD->getAttr<CFReturnsRetainedAttr>())
Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
else if (MD->getAttr<CFReturnsNotRetainedAttr>())
Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
}
}
RetainSummary*

View File

@ -18,7 +18,6 @@ add_clang_library(clangChecker
CheckDeadStores.cpp
CheckObjCDealloc.cpp
CheckObjCInstMethSignature.cpp
CheckObjCUnusedIVars.cpp
CheckSecuritySyntaxOnly.cpp
CheckSizeofPointer.cpp
Checker.cpp
@ -35,6 +34,7 @@ add_clang_library(clangChecker
GRExprEngineExperimentalChecks.cpp
GRState.cpp
LLVMConventionsChecker.cpp
MacOSXAPIChecker.cpp
MallocChecker.cpp
ManagerRegistry.cpp
MemRegion.cpp
@ -42,6 +42,7 @@ add_clang_library(clangChecker
NSErrorChecker.cpp
NoReturnFunctionChecker.cpp
OSAtomicChecker.cpp
ObjCUnusedIVarsChecker.cpp
PathDiagnostic.cpp
PointerArithChecker.cpp
PointerSubChecker.cpp
@ -62,6 +63,7 @@ add_clang_library(clangChecker
UndefResultChecker.cpp
UndefinedArraySubscriptChecker.cpp
UndefinedAssignmentChecker.cpp
UnixAPIChecker.cpp
VLASizeChecker.cpp
ValueManager.cpp
)

View File

@ -26,7 +26,6 @@ class CallInliner : public Checker {
}
virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng);
};
}
@ -43,71 +42,13 @@ bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
if (!FD)
return false;
if (!FD->isThisDeclarationADefinition())
if (!FD->getBody(FD))
return false;
GRStmtNodeBuilder &Builder = C.getNodeBuilder();
// Make a new LocationContext.
const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD,
C.getPredecessor()->getLocationContext(), CE,
Builder.getBlock(), Builder.getIndex());
CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry());
assert (Entry->empty() && "Entry block must be empty.");
assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");
// Get the solitary successor.
CFGBlock const *SuccB = *(Entry->succ_begin());
// Construct an edge representing the starting location in the function.
BlockEdge Loc(Entry, SuccB, LocCtx);
state = C.getStoreManager().EnterStackFrame(state, LocCtx);
// This is a hack. We really should not use the GRStmtNodeBuilder.
bool isNew;
GRExprEngine &Eng = C.getEngine();
ExplodedNode *Pred = C.getPredecessor();
ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew);
SuccN->addPredecessor(Pred, Eng.getGraph());
C.getNodeBuilder().Deferred.erase(Pred);
if (isNew)
Builder.getWorkList()->Enqueue(SuccN);
Builder.HasGeneratedNode = true;
// Now we have the definition of the callee, create a CallEnter node.
CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext());
C.addTransition(state, Loc);
return true;
}
void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
GRExprEngine &Eng) {
const GRState *state = B.getState();
ExplodedNode *Pred = B.getPredecessor();
const StackFrameContext *LocCtx =
cast<StackFrameContext>(Pred->getLocationContext());
const Stmt *CE = LocCtx->getCallSite();
// Check if this is the top level stack frame.
if (!LocCtx->getParent())
return;
PostStmt NodeLoc(CE, LocCtx->getParent());
bool isNew;
ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew);
Succ->addPredecessor(Pred, Eng.getGraph());
// When creating the new work list unit, increment the statement index to
// point to the statement after the CallExpr.
if (isNew)
B.getWorkList().Enqueue(Succ,
*const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
LocCtx->getIndex() + 1);
B.HasGeneratedNode = true;
}

View File

@ -142,7 +142,8 @@ class DeadStoreObs : public LiveVariables::ObserverTy {
if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
// Special case: check for assigning null to a pointer.
// This is a common form of defensive programming.
if (VD->getType()->isPointerType()) {
QualType T = VD->getType();
if (T->isPointerType() || T->isObjCObjectPointerType()) {
if (B->getRHS()->isNullPointerConstant(Ctx,
Expr::NPC_ValueDependentIsNull))
return;

View File

@ -97,7 +97,7 @@ SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R,
if (R->hasStackNonParametersStorage())
return UndefinedVal();
else
return ValMgr.getRegionValueSymbolVal(R, T);
return ValMgr.getRegionValueSymbolVal(cast<TypedRegion>(R));
}
Store FlatStoreManager::Bind(Store store, Loc L, SVal val) {

View File

@ -144,6 +144,14 @@ void GRCoreEngine::ProcessSwitch(GRSwitchNodeBuilder& Builder) {
SubEngine.ProcessSwitch(Builder);
}
void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) {
SubEngine.ProcessCallEnter(Builder);
}
void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) {
SubEngine.ProcessCallExit(Builder);
}
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
@ -196,6 +204,15 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
assert (false && "BlockExit location never occur in forward analysis.");
break;
case ProgramPoint::CallEnterKind:
HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(),
WU.getIndex(), Node);
break;
case ProgramPoint::CallExitKind:
HandleCallExit(cast<CallExit>(Node->getLocation()), Node);
break;
default:
assert(isa<PostStmt>(Node->getLocation()));
HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
@ -207,6 +224,17 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
return WList->hasWork();
}
void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
unsigned Index, ExplodedNode *Pred) {
GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(),
Block, Index);
ProcessCallEnter(Builder);
}
void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) {
GRCallExitNodeBuilder Builder(*this, Pred);
ProcessCallExit(Builder);
}
void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
@ -384,11 +412,11 @@ void GRCoreEngine::GenerateNode(const ProgramPoint& Loc,
GRStmtNodeBuilder::GRStmtNodeBuilder(CFGBlock* b, unsigned idx,
ExplodedNode* N, GRCoreEngine* e,
GRStateManager &mgr)
: Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N), Mgr(mgr), Auditor(0),
: Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr), Auditor(0),
PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false),
PointKind(ProgramPoint::PostStmtKind), Tag(0) {
Deferred.insert(N);
CleanedState = getLastNode()->getState();
CleanedState = Pred->getState();
}
GRStmtNodeBuilder::~GRStmtNodeBuilder() {
@ -400,6 +428,14 @@ GRStmtNodeBuilder::~GRStmtNodeBuilder() {
void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
assert (!N->isSink());
// Check if this node entered a callee.
if (isa<CallEnter>(N->getLocation())) {
// Still use the index of the CallExpr. It's needed to create the callee
// StackFrameContext.
Eng.WList->Enqueue(N, B, Idx);
return;
}
PostStmt Loc(getStmt(), N->getLocationContext());
if (Loc == N->getLocation()) {
@ -462,11 +498,9 @@ GRStmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
if (IsNew) {
Deferred.insert(N);
LastNode = N;
return N;
}
LastNode = NULL;
return NULL;
}
@ -576,7 +610,13 @@ GRSwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) {
GREndPathNodeBuilder::~GREndPathNodeBuilder() {
// Auto-generate an EOP node if one has not been generated.
if (!HasGeneratedNode) generateNode(Pred->State);
if (!HasGeneratedNode) {
// If we are in an inlined call, generate CallExit node.
if (Pred->getLocationContext()->getParent())
GenerateCallExitNode(Pred->State);
else
generateNode(Pred->State);
}
}
ExplodedNode*
@ -597,3 +637,57 @@ GREndPathNodeBuilder::generateNode(const GRState* State, const void *tag,
return NULL;
}
void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) {
HasGeneratedNode = true;
// Create a CallExit node and enqueue it.
const StackFrameContext *LocCtx
= cast<StackFrameContext>(Pred->getLocationContext());
const Stmt *CE = LocCtx->getCallSite();
// Use the the callee location context.
CallExit Loc(CE, LocCtx);
bool isNew;
ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
Node->addPredecessor(Pred, *Eng.G);
if (isNew)
Eng.WList->Enqueue(Node);
}
void GRCallEnterNodeBuilder::GenerateNode(const GRState *state,
const LocationContext *LocCtx) {
// Get the callee entry block.
const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry());
assert(Entry->empty());
assert(Entry->succ_size() == 1);
// Get the solitary successor.
const CFGBlock *SuccB = *(Entry->succ_begin());
// Construct an edge representing the starting location in the callee.
BlockEdge Loc(Entry, SuccB, LocCtx);
bool isNew;
ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
if (isNew)
Eng.WList->Enqueue(Node);
}
void GRCallExitNodeBuilder::GenerateNode(const GRState *state) {
// Get the callee's location context.
const StackFrameContext *LocCtx
= cast<StackFrameContext>(Pred->getLocationContext());
PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent());
bool isNew;
ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
if (isNew)
Eng.WList->Enqueue(Node, *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
LocCtx->getIndex() + 1);
}

View File

@ -37,6 +37,15 @@ using llvm::dyn_cast_or_null;
using llvm::cast;
using llvm::APSInt;
namespace {
// Trait class for recording returned expression in the state.
struct ReturnExpr {
static int TagInt;
typedef const Stmt *data_type;
};
int ReturnExpr::TagInt;
}
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
@ -318,6 +327,8 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
RegisterNoReturnFunctionChecker(Eng);
RegisterBuiltinFunctionChecker(Eng);
RegisterOSAtomicChecker(Eng);
RegisterUnixAPIChecker(Eng);
RegisterMacOSXAPIChecker(Eng);
}
GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
@ -458,7 +469,7 @@ void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
"Error evaluating statement");
Builder = &builder;
EntryNode = builder.getLastNode();
EntryNode = builder.getBasePredecessor();
// Set up our simple checks.
if (BatchAuditor)
@ -1288,6 +1299,37 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt);
}
void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) {
const FunctionDecl *FD = B.getCallee();
const StackFrameContext *LocCtx = AMgr.getStackFrame(FD,
B.getLocationContext(),
B.getCallExpr(),
B.getBlock(),
B.getIndex());
const GRState *state = B.getState();
state = getStoreManager().EnterStackFrame(state, LocCtx);
B.GenerateNode(state, LocCtx);
}
void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) {
const GRState *state = B.getState();
const ExplodedNode *Pred = B.getPredecessor();
const StackFrameContext *LocCtx =
cast<StackFrameContext>(Pred->getLocationContext());
const Stmt *CE = LocCtx->getCallSite();
// If the callee returns an expression, bind its value to CallExpr.
const Stmt *ReturnedExpr = state->get<ReturnExpr>();
if (ReturnedExpr) {
SVal RetVal = state->getSVal(ReturnedExpr);
state = state->BindExpr(CE, RetVal);
}
B.GenerateNode(state);
}
//===----------------------------------------------------------------------===//
// Transfer functions: logical operations ('&&', '||').
//===----------------------------------------------------------------------===//
@ -2316,8 +2358,9 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
if (InitVal.isUnknown() ||
!getConstraintManager().canReasonAbout(InitVal)) {
if ((InitVal.isUnknown() ||
!getConstraintManager().canReasonAbout(InitVal)) &&
!VD->getType()->isReferenceType()) {
InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
Builder->getCurrentBlockCount());
}
@ -2855,10 +2898,19 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ExplodedNodeSet Src;
if (Expr *RetE = RS->getRetValue()) {
Visit(RetE, Pred, Src);
// Record the returned expression in the state.
{
static int Tag = 0;
SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag);
const GRState *state = GetState(Pred);
state = state->set<ReturnExpr>(RetE);
Pred = Builder->generateNode(RetE, state, Pred);
}
// We may get a NULL Pred because we generated a cached node.
if (Pred)
Visit(RetE, Pred, Src);
}
else {
Src.Add(Pred);
@ -3139,6 +3191,14 @@ struct DOTGraphTraits<ExplodedNode*> :
assert (false);
break;
case ProgramPoint::CallEnterKind:
Out << "CallEnter";
break;
case ProgramPoint::CallExitKind:
Out << "CallExit";
break;
default: {
if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
const Stmt* S = L->getStmt();

View File

@ -19,27 +19,33 @@ namespace clang {
class GRExprEngine;
// Foundational checks that handle basic semantics.
void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng);
void RegisterArrayBoundChecker(GRExprEngine &Eng);
void RegisterAttrNonNullChecker(GRExprEngine &Eng);
void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
void RegisterCallAndMessageChecker(GRExprEngine &Eng);
void RegisterCastToStructChecker(GRExprEngine &Eng);
void RegisterDereferenceChecker(GRExprEngine &Eng);
void RegisterDivZeroChecker(GRExprEngine &Eng);
void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
void RegisterReturnStackAddressChecker(GRExprEngine &Eng);
void RegisterReturnUndefChecker(GRExprEngine &Eng);
void RegisterVLASizeChecker(GRExprEngine &Eng);
void RegisterPointerSubChecker(GRExprEngine &Eng);
void RegisterPointerArithChecker(GRExprEngine &Eng);
void RegisterFixedAddressChecker(GRExprEngine &Eng);
void RegisterCastToStructChecker(GRExprEngine &Eng);
void RegisterCallAndMessageChecker(GRExprEngine &Eng);
void RegisterArrayBoundChecker(GRExprEngine &Eng);
void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
void RegisterPointerArithChecker(GRExprEngine &Eng);
void RegisterPointerSubChecker(GRExprEngine &Eng);
void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
void RegisterReturnStackAddressChecker(GRExprEngine &Eng);
void RegisterReturnUndefChecker(GRExprEngine &Eng);
void RegisterUndefBranchChecker(GRExprEngine &Eng);
void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng);
void RegisterUndefResultChecker(GRExprEngine &Eng);
void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
void RegisterVLASizeChecker(GRExprEngine &Eng);
// API checks.
void RegisterMacOSXAPIChecker(GRExprEngine &Eng);
void RegisterOSAtomicChecker(GRExprEngine &Eng);
void RegisterUnixAPIChecker(GRExprEngine &Eng);
} // end clang namespace
#endif

View File

@ -0,0 +1,141 @@
// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This defines MacOSXAPIChecker, which is an assortment of checks on calls
// to various, widely used Mac OS X functions.
//
// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
// to here, using the new Checker interface.
//
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
enum SubChecks {
DispatchOnce = 0,
DispatchOnceF,
NumChecks
};
BugType *BTypes[NumChecks];
public:
MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
static void *getTag() { static unsigned tag = 0; return &tag; }
void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
};
} //end anonymous namespace
void clang::RegisterMacOSXAPIChecker(GRExprEngine &Eng) {
if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
Eng.registerCheck(new MacOSXAPIChecker());
}
//===----------------------------------------------------------------------===//
// dispatch_once and dispatch_once_f
//===----------------------------------------------------------------------===//
static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
BugType *&BT, const IdentifierInfo *FI) {
if (!BT) {
llvm::SmallString<128> S;
llvm::raw_svector_ostream os(S);
os << "Improper use of '" << FI->getName() << '\'';
BT = new BugType(os.str(), "Mac OS X API");
}
if (CE->getNumArgs() < 1)
return;
// Check if the first argument is stack allocated. If so, issue a warning
// because that's likely to be bad news.
const GRState *state = C.getState();
const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
return;
ExplodedNode *N = C.GenerateSink(state);
if (!N)
return;
llvm::SmallString<256> S;
llvm::raw_svector_ostream os(S);
os << "Call to '" << FI->getName() << "' uses";
if (const VarRegion *VR = dyn_cast<VarRegion>(R))
os << " the local variable '" << VR->getDecl()->getName() << '\'';
else
os << " stack allocated memory";
os << " for the predicate value. Using such transient memory for "
"the predicate is potentially dangerous.";
if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
os << " Perhaps you intended to declare the variable as 'static'?";
EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
C.EmitReport(report);
}
//===----------------------------------------------------------------------===//
// Central dispatch function.
//===----------------------------------------------------------------------===//
typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT,
const IdentifierInfo *FI);
namespace {
class SubCheck {
SubChecker SC;
BugType **BT;
public:
SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
SubCheck() : SC(NULL), BT(NULL) {}
void run(CheckerContext &C, const CallExpr *CE,
const IdentifierInfo *FI) const {
if (SC)
SC(C, CE, *BT, FI);
}
};
} // end anonymous namespace
void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
// FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor.
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionTextRegion *Fn =
dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
if (!Fn)
return;
const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
if (!FI)
return;
const SubCheck &SC =
llvm::StringSwitch<SubCheck>(FI->getName())
.Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
.Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
BTypes[DispatchOnceF]))
.Default(SubCheck());
SC.run(C, CE, FI);
}

View File

@ -419,20 +419,27 @@ const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
const StackLocalsSpaceRegion*
MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
assert(STC);
if (STC == cachedStackLocalsFrame)
return cachedStackLocalsRegion;
cachedStackLocalsFrame = STC;
return LazyAllocate(cachedStackLocalsRegion, STC);
StackLocalsSpaceRegion *&R = StackLocalsSpaceRegions[STC];
if (R)
return R;
R = A.Allocate<StackLocalsSpaceRegion>();
new (R) StackLocalsSpaceRegion(this, STC);
return R;
}
const StackArgumentsSpaceRegion *
MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
assert(STC);
if (STC == cachedStackArgumentsFrame)
return cachedStackArgumentsRegion;
cachedStackArgumentsFrame = STC;
return LazyAllocate(cachedStackArgumentsRegion, STC);
StackArgumentsSpaceRegion *&R = StackArgumentsSpaceRegions[STC];
if (R)
return R;
R = A.Allocate<StackArgumentsSpaceRegion>();
new (R) StackArgumentsSpaceRegion(this, STC);
return R;
}
const GlobalsSpaceRegion *MemRegionManager::getGlobalsRegion() {

View File

@ -14,7 +14,6 @@
#include "GRExprEngineInternalChecks.h"
#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;

View File

@ -1,4 +1,4 @@
//==- CheckObjCUnusedIVars.cpp - Check for unused ivars ----------*- C++ -*-==//
//==- ObjCUnusedIVarsChecker.cpp - Check for unused ivars --------*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
@ -68,14 +68,14 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(),
E = D->instmeth_end(); I!=E; ++I)
Scan(M, (*I)->getBody());
if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {
if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {
// Scan for @synthesized property methods that act as setters/getters
// to an ivar.
for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(),
E = ID->propimpl_end(); I!=E; ++I)
Scan(M, *I);
// Scan the associated categories as well.
for (const ObjCCategoryDecl *CD =
ID->getClassInterface()->getCategoryList(); CD ;
@ -92,7 +92,7 @@ static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
I!=E; ++I)
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
SourceLocation L = FD->getLocStart();
if (SM.getFileID(L) == FID)
if (SM.getFileID(L) == FID)
Scan(M, FD->getBody());
}
}
@ -109,12 +109,12 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
const ObjCIvarDecl* ID = *I;
// Ignore ivars that aren't private.
if (ID->getAccessControl() != ObjCIvarDecl::Private)
continue;
// Skip IB Outlets.
if (ID->getAttr<IBOutletAttr>())
// Ignore ivars that...
// (a) aren't private
// (b) explicitly marked unused
// (c) are iboutlets
if (ID->getAccessControl() != ObjCIvarDecl::Private ||
ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>())
continue;
M[ID] = Unused;
@ -122,11 +122,10 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
if (M.empty())
return;
// Now scan the implementation declaration.
Scan(M, D);
// Any potentially unused ivars?
bool hasUnused = false;
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
@ -134,10 +133,10 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
hasUnused = true;
break;
}
if (!hasUnused)
return;
// We found some potentially unused ivars. Scan the entire translation unit
// for functions inside the @implementation that reference these ivars.
// FIXME: In the future hopefully we can just use the lexical DeclContext

Some files were not shown because too many files have changed in this diff Show More