Update clang to 97654.
This commit is contained in:
parent
ecb7e5c8af
commit
79ade4e028
@ -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; };
|
||||
|
@ -1,3 +1,4 @@
|
||||
add_subdirectory(clang-interpreter)
|
||||
add_subdirectory(PrintFunctionNames)
|
||||
add_subdirectory(wpa)
|
||||
|
||||
|
@ -9,6 +9,6 @@
|
||||
|
||||
LEVEL = ../../..
|
||||
|
||||
PARALLEL_DIRS := PrintFunctionNames wpa
|
||||
PARALLEL_DIRS := clang-interpreter PrintFunctionNames wpa
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
30
examples/clang-interpreter/CMakeLists.txt
Normal file
30
examples/clang-interpreter/CMakeLists.txt
Normal 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)
|
30
examples/clang-interpreter/Makefile
Normal file
30
examples/clang-interpreter/Makefile
Normal 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
|
17
examples/clang-interpreter/README.txt
Normal file
17
examples/clang-interpreter/README.txt
Normal 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.
|
152
examples/clang-interpreter/main.cpp
Normal file
152
examples/clang-interpreter/main.cpp
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
/// 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 @@ public:
|
||||
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);
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -62,7 +62,8 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
WarnUnusedResult,
|
||||
Weak,
|
||||
WeakImport,
|
||||
WeakRef,
|
||||
|
||||
FIRST_TARGET_ATTRIBUTE,
|
||||
DLLExport,
|
||||
@ -300,19 +304,6 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
};
|
||||
|
||||
// Checker-specific attributes.
|
||||
DEF_SIMPLE_ATTR(CFReturnsNotRetained);
|
||||
DEF_SIMPLE_ATTR(CFReturnsRetained);
|
||||
DEF_SIMPLE_ATTR(NSReturnsNotRetained);
|
||||
DEF_SIMPLE_ATTR(NSReturnsRetained);
|
||||
|
||||
// C++0x member checking attributes.
|
||||
|
@ -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;
|
||||
|
@ -120,6 +120,13 @@ public:
|
||||
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 @@ public:
|
||||
/// 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));
|
||||
|
@ -267,8 +267,8 @@ public:
|
||||
}
|
||||
|
||||
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 @@ public:
|
||||
|
||||
/// \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 @@ public:
|
||||
|
||||
/// \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()); }
|
||||
|
@ -279,7 +279,8 @@ public:
|
||||
|
||||
/// \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 @@ public:
|
||||
return const_cast<Decl*>(this)->getLexicalDeclContext();
|
||||
}
|
||||
|
||||
bool isOutOfLine() const {
|
||||
virtual bool isOutOfLine() const {
|
||||
return getLexicalDeclContext() != getDeclContext();
|
||||
}
|
||||
|
||||
|
@ -710,7 +710,7 @@ public:
|
||||
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 @@ public:
|
||||
/// 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 @@ public:
|
||||
/// 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.
|
||||
|
@ -494,11 +494,13 @@ public:
|
||||
}
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
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; }
|
||||
|
||||
|
@ -150,7 +150,8 @@ public:
|
||||
LV_InvalidExpression,
|
||||
LV_MemberFunction,
|
||||
LV_SubObjCPropertySetting,
|
||||
LV_SubObjCPropertyGetterSetting
|
||||
LV_SubObjCPropertyGetterSetting,
|
||||
LV_ClassTemporary
|
||||
};
|
||||
isLvalueResult isLvalue(ASTContext &Ctx) const;
|
||||
|
||||
@ -181,7 +182,8 @@ public:
|
||||
MLV_NoSetterProperty,
|
||||
MLV_MemberFunction,
|
||||
MLV_SubObjCPropertySetting,
|
||||
MLV_SubObjCPropertyGetterSetting
|
||||
MLV_SubObjCPropertyGetterSetting,
|
||||
MLV_ClassTemporary
|
||||
};
|
||||
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
|
||||
SourceLocation *Loc = 0) const;
|
||||
|
@ -997,21 +997,59 @@ public:
|
||||
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 @@ public:
|
||||
/// \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;
|
||||
|
@ -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 @@ public:
|
||||
/// \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; }
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -75,11 +75,14 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
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,
|
||||
|
55
include/clang/Analysis/Analyses/ReachableCode.h
Normal file
55
include/clang/Analysis/Analyses/ReachableCode.h
Normal 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
|
@ -110,6 +110,8 @@ public:
|
||||
|
||||
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(); }
|
||||
|
@ -245,8 +245,6 @@ public:
|
||||
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;
|
||||
|
@ -26,6 +26,7 @@
|
||||
namespace clang {
|
||||
|
||||
class LocationContext;
|
||||
class FunctionDecl;
|
||||
|
||||
class ProgramPoint {
|
||||
public:
|
||||
@ -41,6 +42,8 @@ public:
|
||||
PostPurgeDeadSymbolsKind,
|
||||
PostStmtCustomKind,
|
||||
PostLValueKind,
|
||||
CallEnterKind,
|
||||
CallExitKind,
|
||||
MinPostStmtKind = PostStmtKind,
|
||||
MaxPostStmtKind = PostLValueKind };
|
||||
|
||||
@ -308,6 +311,36 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
@ -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")
|
||||
|
@ -403,13 +403,6 @@ public:
|
||||
/// \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 @@ public:
|
||||
/// 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
|
||||
|
@ -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">;
|
||||
}
|
||||
|
@ -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">;
|
||||
|
||||
}
|
||||
|
@ -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<
|
||||
|
@ -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]>;
|
||||
|
@ -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<
|
||||
|
@ -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<
|
||||
|
@ -59,7 +59,6 @@ public:
|
||||
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 @@ public:
|
||||
ThreadsafeStatics = 1;
|
||||
POSIXThreads = 0;
|
||||
Blocks = 0;
|
||||
BlockIntrospection = 0;
|
||||
EmitAllDecls = 0;
|
||||
MathErrno = 1;
|
||||
|
||||
@ -156,7 +154,7 @@ public:
|
||||
OverflowChecking = 0;
|
||||
ObjCGCBitmapPrint = 0;
|
||||
|
||||
InstantiationDepth = 99;
|
||||
InstantiationDepth = 500;
|
||||
|
||||
Optimize = 0;
|
||||
OptimizeSize = 0;
|
||||
|
@ -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);
|
||||
|
@ -147,12 +147,22 @@ public:
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
@ -171,7 +171,13 @@ public:
|
||||
/// 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);
|
||||
|
@ -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 @@ public:
|
||||
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:
|
||||
|
@ -28,6 +28,8 @@ class GRBranchNodeBuilder;
|
||||
class GRIndirectGotoNodeBuilder;
|
||||
class GRSwitchNodeBuilder;
|
||||
class GREndPathNodeBuilder;
|
||||
class GRCallEnterNodeBuilder;
|
||||
class GRCallExitNodeBuilder;
|
||||
class LocationContext;
|
||||
|
||||
class GRSubEngine {
|
||||
@ -64,6 +66,12 @@ public:
|
||||
/// 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.
|
||||
|
@ -428,7 +428,6 @@ public:
|
||||
/// 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();
|
||||
|
||||
|
@ -89,27 +89,23 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// A symbol representing the result of an expression.
|
||||
class SymbolConjured : public SymbolData {
|
||||
const Stmt* S;
|
||||
QualType T;
|
||||
@ -161,6 +158,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// 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 @@ public:
|
||||
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);
|
||||
|
@ -94,8 +94,7 @@ public:
|
||||
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);
|
||||
|
@ -53,6 +53,8 @@ public:
|
||||
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 @@ public:
|
||||
UnrollLoops = 0;
|
||||
UnwindTables = 0;
|
||||
VerifyModule = 1;
|
||||
CXXCtorDtorAliases = 0;
|
||||
|
||||
Inlining = NoInlining;
|
||||
RelocationModel = "pic";
|
||||
|
@ -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">;
|
||||
|
||||
|
@ -70,6 +70,9 @@ public:
|
||||
/// 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 @@ public:
|
||||
|
||||
void setCheckInputsExist(bool Value) { CheckInputsExist = Value; }
|
||||
|
||||
const std::string &getTitle() { return DriverTitle; }
|
||||
void setTitle(std::string Value) { DriverTitle = Value; }
|
||||
|
||||
/// @}
|
||||
/// @name Primary Functionality
|
||||
/// @{
|
||||
|
@ -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]>;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
// 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 @@ public:
|
||||
llvm::StringRef ResourceFilesPath,
|
||||
bool OnlyLocalDecls = false,
|
||||
RemappedFile *RemappedFiles = 0,
|
||||
unsigned NumRemappedFiles = 0);
|
||||
unsigned NumRemappedFiles = 0,
|
||||
bool CaptureDiagnostics = false);
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
65
include/clang/Frontend/CodeGenAction.h
Normal file
65
include/clang/Frontend/CodeGenAction.h
Normal 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();
|
||||
};
|
||||
|
||||
}
|
@ -158,46 +158,6 @@ public:
|
||||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -570,6 +570,12 @@ public:
|
||||
/// 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 {
|
||||
|
@ -327,13 +327,26 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
//===------------------------- 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 @@ public:
|
||||
/// 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();
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,8 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
AT_visibility,
|
||||
AT_warn_unused_result,
|
||||
AT_weak,
|
||||
AT_weakref,
|
||||
AT_weak_import,
|
||||
AT_reqd_wg_size,
|
||||
IgnoredAttribute,
|
||||
|
@ -320,86 +320,39 @@ private:
|
||||
/// 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 @@ private:
|
||||
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 @@ private:
|
||||
|
||||
bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
||||
TypeTy *ObjectType,
|
||||
bool EnteringContext);
|
||||
bool EnteringContext,
|
||||
bool *MayBePseudoDestructor = 0);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ 5.2p1: C++ Casts
|
||||
@ -972,6 +927,13 @@ private:
|
||||
// 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 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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 @@ private:
|
||||
SourceLocation NameLoc,
|
||||
bool EnteringContext,
|
||||
TypeTy *ObjectType,
|
||||
UnqualifiedId &Id);
|
||||
UnqualifiedId &Id,
|
||||
bool AssumeTemplateId = false);
|
||||
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
|
||||
TypeTy *ObjectType,
|
||||
UnqualifiedId &Result);
|
||||
|
@ -129,6 +129,9 @@ private:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
DeclsInScope.clear();
|
||||
UsingDirectives.clear();
|
||||
Entity = 0;
|
||||
NumErrorsAtStart = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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 &&
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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]);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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.
|
||||
|
@ -5,6 +5,7 @@ add_clang_library(clangAnalysis
|
||||
CFG.cpp
|
||||
LiveVariables.cpp
|
||||
PrintfFormatString.cpp
|
||||
ReachableCode.cpp
|
||||
UninitializedValues.cpp
|
||||
)
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
278
lib/Analysis/ReachableCode.cpp
Normal file
278
lib/Analysis/ReachableCode.cpp
Normal 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
|
@ -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:
|
||||
//
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 @@ public:
|
||||
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:
|
||||
|
@ -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() {
|
||||
|
@ -95,6 +95,8 @@ public:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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*
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -26,7 +26,6 @@ public:
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -142,7 +142,8 @@ public:
|
||||
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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
141
lib/Checker/MacOSXAPIChecker.cpp
Normal file
141
lib/Checker/MacOSXAPIChecker.cpp
Normal 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);
|
||||
}
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user