Vendor import of clang trunk r126079:
http://llvm.org/svn/llvm-project/cfe/trunk@126079
This commit is contained in:
parent
998bc5802e
commit
bca07a4524
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=218887 svn path=/vendor/clang/clang-r126079/; revision=218888; tag=vendor/clang/clang-r126079
122
CMakeLists.txt
122
CMakeLists.txt
@ -1,4 +1,67 @@
|
||||
# Clang version information
|
||||
# If we are not building as a part of LLVM, build Clang as an
|
||||
# standalone project, using LLVM as an external library:
|
||||
if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
||||
project(Clang)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(CLANG_PATH_TO_LLVM_SOURCE "" CACHE PATH
|
||||
"Path to LLVM source code. Not necessary if using an installed LLVM.")
|
||||
set(CLANG_PATH_TO_LLVM_BUILD "" CACHE PATH
|
||||
"Path to the directory where LLVM was built or installed.")
|
||||
|
||||
if( CLANG_PATH_TO_LLVM_SOURCE )
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_SOURCE}/cmake/config-ix.cmake" )
|
||||
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_SOURCE to the root directory of LLVM source code.")
|
||||
else()
|
||||
get_filename_component(LLVM_MAIN_SRC_DIR ${CLANG_PATH_TO_LLVM_SOURCE}
|
||||
ABSOLUTE)
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake")
|
||||
|
||||
get_filename_component(PATH_TO_LLVM_BUILD ${CLANG_PATH_TO_LLVM_BUILD}
|
||||
ABSOLUTE)
|
||||
|
||||
include(AddLLVM)
|
||||
include(TableGen)
|
||||
include("${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVM.cmake")
|
||||
include(HandleLLVMOptions)
|
||||
|
||||
set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
|
||||
|
||||
set(LLVM_MAIN_INCLUDE_DIR "${LLVM_MAIN_SRC_DIR}/include")
|
||||
set(LLVM_BINARY_DIR ${CMAKE_BINARY_DIR})
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}")
|
||||
if( NOT PATH_TO_LLVM_BUILD STREQUAL LLVM_MAIN_SRC_DIR )
|
||||
include_directories("${LLVM_MAIN_INCLUDE_DIR}")
|
||||
endif()
|
||||
link_directories("${PATH_TO_LLVM_BUILD}/lib")
|
||||
|
||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/tblgen")
|
||||
|
||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
|
||||
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
|
||||
add_definitions( -D__STDC_LIMIT_MACROS )
|
||||
add_definitions( -D__STDC_CONSTANT_MACROS )
|
||||
|
||||
set( CLANG_BUILT_STANDALONE 1 )
|
||||
endif()
|
||||
|
||||
set(CLANG_RESOURCE_DIR "" CACHE STRING
|
||||
"Relative directory from the Clang binary to its resource files.")
|
||||
|
||||
set(C_INCLUDE_DIRS "" CACHE STRING
|
||||
"Colon separated list of directories clang will search for headers.")
|
||||
|
||||
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
@ -24,7 +87,7 @@ if( NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
|
||||
endif()
|
||||
|
||||
# Compute the Clang version from the LLVM version.
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||
${PACKAGE_VERSION})
|
||||
message(STATUS "Clang version: ${CLANG_VERSION}")
|
||||
|
||||
@ -47,23 +110,26 @@ configure_file(
|
||||
|
||||
# Add appropriate flags for GCC
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
# FIXME: Turn off exceptions, RTTI:
|
||||
# -fno-exceptions -fno-rtti
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings")
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
|
||||
endif ()
|
||||
|
||||
configure_file(
|
||||
${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
|
||||
${CLANG_BINARY_DIR}/include/clang/Config/config.h)
|
||||
|
||||
macro(add_clang_library name)
|
||||
set(srcs ${ARGN})
|
||||
llvm_process_sources(srcs ${ARGN})
|
||||
if(MSVC_IDE OR XCODE)
|
||||
file( GLOB_RECURSE headers *.h *.td *.def)
|
||||
set(srcs ${srcs} ${headers})
|
||||
string( REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list( GET split_path -1 dir)
|
||||
file( GLOB_RECURSE headers
|
||||
file( GLOB_RECURSE headers
|
||||
../../../include/clang/StaticAnalyzer${dir}/*.h
|
||||
../../../include/clang/StaticAnalyzer${dir}/*.td
|
||||
../../../include/clang/StaticAnalyzer${dir}/*.def
|
||||
../../include/clang${dir}/*.h
|
||||
../../include/clang${dir}/*.td
|
||||
../../include/clang${dir}/*.def)
|
||||
@ -88,10 +154,15 @@ macro(add_clang_library name)
|
||||
if( LLVM_LINK_COMPONENTS )
|
||||
llvm_config(${name} ${LLVM_LINK_COMPONENTS})
|
||||
endif( LLVM_LINK_COMPONENTS )
|
||||
get_system_libs(llvm_system_libs)
|
||||
if( llvm_system_libs )
|
||||
target_link_libraries(${name} ${llvm_system_libs})
|
||||
endif( llvm_system_libs )
|
||||
if (LLVM_COMMON_LIBS)
|
||||
target_link_libraries(${name} ${LLVM_COMMON_LIBS})
|
||||
endif()
|
||||
if( NOT MINGW )
|
||||
get_system_libs(llvm_system_libs)
|
||||
if( llvm_system_libs )
|
||||
target_link_libraries(${name} ${llvm_system_libs})
|
||||
endif()
|
||||
endif()
|
||||
add_dependencies(${name} ClangDiagnosticCommon)
|
||||
if(MSVC)
|
||||
get_target_property(cflag ${name} COMPILE_FLAGS)
|
||||
@ -107,12 +178,7 @@ macro(add_clang_library name)
|
||||
endmacro(add_clang_library)
|
||||
|
||||
macro(add_clang_executable name)
|
||||
set(srcs ${ARGN})
|
||||
if(MSVC_IDE)
|
||||
file( GLOB_RECURSE headers *.h *.td *.def)
|
||||
set(srcs ${srcs} ${headers})
|
||||
endif(MSVC_IDE)
|
||||
add_llvm_executable( ${name} ${srcs} )
|
||||
add_llvm_executable( ${name} ${ARGN} )
|
||||
endmacro(add_clang_executable)
|
||||
|
||||
include_directories(
|
||||
@ -136,7 +202,7 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
|
||||
PATTERN "*.inc"
|
||||
)
|
||||
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
add_definitions( -D_GNU_SOURCE -DHAVE_CLANG_CONFIG_H )
|
||||
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs." OFF)
|
||||
if(CLANG_BUILD_EXAMPLES)
|
||||
@ -146,7 +212,23 @@ endif ()
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(runtime)
|
||||
|
||||
# TODO: docs.
|
||||
if( LLVM_INCLUDE_TESTS )
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
# FIXME: unittests require gtest.
|
||||
if( NOT CLANG_BUILT_STANDALONE )
|
||||
add_subdirectory(unittests)
|
||||
endif()
|
||||
|
||||
# Workaround for MSVS10 to avoid the Dialog Hell
|
||||
# FIXME: This could be removed with future version of CMake.
|
||||
if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 )
|
||||
set(CLANG_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/Clang.sln")
|
||||
if( EXISTS "${CLANG_SLN_FILENAME}" )
|
||||
file(APPEND "${CLANG_SLN_FILENAME}" "\n# This should be regenerated!\n")
|
||||
endif()
|
||||
endif()
|
||||
|
18
Makefile
18
Makefile
@ -14,7 +14,7 @@ ifndef CLANG_LEVEL
|
||||
|
||||
IS_TOP_LEVEL := 1
|
||||
CLANG_LEVEL := .
|
||||
DIRS := include lib tools runtime docs
|
||||
DIRS := include lib tools runtime docs unittests
|
||||
|
||||
PARALLEL_DIRS :=
|
||||
|
||||
@ -37,6 +37,10 @@ LEVEL := $(CLANG_LEVEL)/../..
|
||||
# Include LLVM common makefile.
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
ifneq ($(ENABLE_DOCS),1)
|
||||
DIRS := $(filter-out docs, $(DIRS))
|
||||
endif
|
||||
|
||||
# Set common Clang build flags.
|
||||
CPP.Flags += -I$(PROJ_SRC_DIR)/$(CLANG_LEVEL)/include -I$(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include
|
||||
ifdef CLANG_VENDOR
|
||||
@ -44,7 +48,7 @@ CPP.Flags += -DCLANG_VENDOR='"$(CLANG_VENDOR) "'
|
||||
endif
|
||||
|
||||
# Disable -fstrict-aliasing. Darwin disables it by default (and LLVM doesn't
|
||||
# work with it enabled with GCC), Clang/llvm-gc don't support it yet, and newer
|
||||
# work with it enabled with GCC), Clang/llvm-gcc don't support it yet, and newer
|
||||
# GCC's have false positive warnings with it on Linux (which prove a pain to
|
||||
# fix). For example:
|
||||
# http://gcc.gnu.org/PR41874
|
||||
@ -60,10 +64,12 @@ ifeq ($(IS_TOP_LEVEL),1)
|
||||
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
$(RecursiveTargets)::
|
||||
$(Verb) if [ ! -f test/Makefile ]; then \
|
||||
$(MKDIR) test; \
|
||||
$(CP) $(PROJ_SRC_DIR)/test/Makefile test/Makefile; \
|
||||
fi
|
||||
$(Verb) for dir in test unittests; do \
|
||||
if [ ! -f $${dir}/Makefile ]; then \
|
||||
$(MKDIR) $${dir}; \
|
||||
$(CP) $(PROJ_SRC_DIR)/$${dir}/Makefile $${dir}/Makefile; \
|
||||
fi \
|
||||
done
|
||||
endif
|
||||
|
||||
test::
|
||||
|
2
TODO.txt
2
TODO.txt
@ -2,7 +2,6 @@
|
||||
// Minor random things that can be improved
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
|
||||
Warn about "X && 0x1000" saying that the user may mean "X & 0x1000".
|
||||
We should do this for any immediate except zero, so long as it doesn't come
|
||||
from a macro expansion. Likewise for ||.
|
||||
@ -73,3 +72,4 @@ Options to support:
|
||||
-fpreprocessed mode.
|
||||
-nostdinc++
|
||||
-imultilib
|
||||
|
||||
|
@ -191,19 +191,19 @@ def __init__(self, ptr):
|
||||
self.ptr = ptr
|
||||
|
||||
def __del__(self):
|
||||
_clang_disposeDiagnostic(self.ptr)
|
||||
_clang_disposeDiagnostic(self)
|
||||
|
||||
@property
|
||||
def severity(self):
|
||||
return _clang_getDiagnosticSeverity(self.ptr)
|
||||
return _clang_getDiagnosticSeverity(self)
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
return _clang_getDiagnosticLocation(self.ptr)
|
||||
return _clang_getDiagnosticLocation(self)
|
||||
|
||||
@property
|
||||
def spelling(self):
|
||||
return _clang_getDiagnosticSpelling(self.ptr)
|
||||
return _clang_getDiagnosticSpelling(self)
|
||||
|
||||
@property
|
||||
def ranges(self):
|
||||
@ -215,9 +215,11 @@ def __len__(self):
|
||||
return int(_clang_getDiagnosticNumRanges(self.diag))
|
||||
|
||||
def __getitem__(self, key):
|
||||
if (key >= len(self)):
|
||||
raise IndexError
|
||||
return _clang_getDiagnosticRange(self.diag, key)
|
||||
|
||||
return RangeIterator(self.ptr)
|
||||
return RangeIterator(self)
|
||||
|
||||
@property
|
||||
def fixits(self):
|
||||
@ -236,12 +238,15 @@ def __getitem__(self, key):
|
||||
|
||||
return FixIt(range, value)
|
||||
|
||||
return FixItIterator(self.ptr)
|
||||
return FixItIterator(self)
|
||||
|
||||
def __repr__(self):
|
||||
return "<Diagnostic severity %r, location %r, spelling %r>" % (
|
||||
self.severity, self.location, self.spelling)
|
||||
|
||||
def from_param(self):
|
||||
return self.ptr
|
||||
|
||||
class FixIt(object):
|
||||
"""
|
||||
A FixIt represents a transformation to be applied to the source to
|
||||
@ -397,6 +402,51 @@ def __repr__(self):
|
||||
# A typedef.
|
||||
CursorKind.TYPEDEF_DECL = CursorKind(20)
|
||||
|
||||
# A C++ class method.
|
||||
CursorKind.CXX_METHOD = CursorKind(21)
|
||||
|
||||
# A C++ namespace.
|
||||
CursorKind.NAMESPACE = CursorKind(22)
|
||||
|
||||
# A linkage specification, e.g. 'extern "C"'.
|
||||
CursorKind.LINKAGE_SPEC = CursorKind(23)
|
||||
|
||||
# A C++ constructor.
|
||||
CursorKind.CONSTRUCTOR = CursorKind(24)
|
||||
|
||||
# A C++ destructor.
|
||||
CursorKind.DESTRUCTOR = CursorKind(25)
|
||||
|
||||
# A C++ conversion function.
|
||||
CursorKind.CONVERSION_FUNCTION = CursorKind(26)
|
||||
|
||||
# A C++ template type parameter
|
||||
CursorKind.TEMPLATE_TYPE_PARAMETER = CursorKind(27)
|
||||
|
||||
# A C++ non-type template paramater.
|
||||
CursorKind.TEMPLATE_NON_TYPE_PARAMETER = CursorKind(28)
|
||||
|
||||
# A C++ template template parameter.
|
||||
CursorKind.TEMPLATE_TEMPLATE_PARAMTER = CursorKind(29)
|
||||
|
||||
# A C++ function template.
|
||||
CursorKind.FUNCTION_TEMPLATE = CursorKind(30)
|
||||
|
||||
# A C++ class template.
|
||||
CursorKind.CLASS_TEMPLATE = CursorKind(31)
|
||||
|
||||
# A C++ class template partial specialization.
|
||||
CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION = CursorKind(32)
|
||||
|
||||
# A C++ namespace alias declaration.
|
||||
CursorKind.NAMESPACE_ALIAS = CursorKind(33)
|
||||
|
||||
# A C++ using directive
|
||||
CursorKind.USING_DIRECTIVE = CursorKind(34)
|
||||
|
||||
# A C++ using declaration
|
||||
CursorKind.USING_DECLARATION = CursorKind(35)
|
||||
|
||||
###
|
||||
# Reference Kinds
|
||||
|
||||
@ -415,6 +465,25 @@ def __repr__(self):
|
||||
# while the type of the variable "size" is referenced. The cursor
|
||||
# referenced by the type of size is the typedef for size_type.
|
||||
CursorKind.TYPE_REF = CursorKind(43)
|
||||
CursorKind.CXX_BASE_SPECIFIER = CursorKind(44)
|
||||
|
||||
# A reference to a class template, function template, template
|
||||
# template parameter, or class template partial specialization.
|
||||
CursorKind.TEMPLATE_REF = CursorKind(45)
|
||||
|
||||
# A reference to a namespace or namepsace alias.
|
||||
CursorKind.NAMESPACE_REF = CursorKind(46)
|
||||
|
||||
# A reference to a member of a struct, union, or class that occurs in
|
||||
# some non-expression context, e.g., a designated initializer.
|
||||
CursorKind.MEMBER_REF = CursorKind(47)
|
||||
|
||||
# A reference to a labeled statement.
|
||||
CursorKind.LABEL_REF = CursorKind(48)
|
||||
|
||||
# A reference toa a set of overloaded functions or function templates
|
||||
# that has not yet been resolved to a specific function or function template.
|
||||
CursorKind.OVERLOADED_DECL_REF = CursorKind(49)
|
||||
|
||||
###
|
||||
# Invalid/Error Kinds
|
||||
@ -422,6 +491,7 @@ def __repr__(self):
|
||||
CursorKind.INVALID_FILE = CursorKind(70)
|
||||
CursorKind.NO_DECL_FOUND = CursorKind(71)
|
||||
CursorKind.NOT_IMPLEMENTED = CursorKind(72)
|
||||
CursorKind.INVALID_CODE = CursorKind(73)
|
||||
|
||||
###
|
||||
# Expression Kinds
|
||||
@ -447,6 +517,9 @@ def __repr__(self):
|
||||
# An expression that sends a message to an Objective-C object or class.
|
||||
CursorKind.OBJC_MESSAGE_EXPR = CursorKind(104)
|
||||
|
||||
# An expression that represents a block literal.
|
||||
CursorKind.BLOCK_EXPR = CursorKind(105)
|
||||
|
||||
# A statement whose specific kind is not exposed via this interface.
|
||||
#
|
||||
# Unexposed statements have the same operations as any other kind of statement;
|
||||
@ -454,6 +527,10 @@ def __repr__(self):
|
||||
# the specific kind of the statement is not reported.
|
||||
CursorKind.UNEXPOSED_STMT = CursorKind(200)
|
||||
|
||||
# A labelled statement in a function.
|
||||
CursorKind.LABEL_STMT = CursorKind(201)
|
||||
|
||||
|
||||
###
|
||||
# Other Kinds
|
||||
|
||||
@ -463,6 +540,23 @@ def __repr__(self):
|
||||
# traversing the contents of a translation unit.
|
||||
CursorKind.TRANSLATION_UNIT = CursorKind(300)
|
||||
|
||||
###
|
||||
# Attributes
|
||||
|
||||
# An attribute whoe specific kind is note exposed via this interface
|
||||
CursorKind.UNEXPOSED_ATTR = CursorKind(400)
|
||||
|
||||
CursorKind.IB_ACTION_ATTR = CursorKind(401)
|
||||
CursorKind.IB_OUTLET_ATTR = CursorKind(402)
|
||||
CursorKind.IB_OUTLET_COLLECTION_ATTR = CursorKind(403)
|
||||
|
||||
###
|
||||
# Preprocessing
|
||||
CursorKind.PREPROCESSING_DIRECTIVE = CursorKind(500)
|
||||
CursorKind.MACRO_DEFINITION = CursorKind(501)
|
||||
CursorKind.MACRO_INSTANTIATION = CursorKind(502)
|
||||
CursorKind.INCLUSION_DIRECTIVE = CursorKind(503)
|
||||
|
||||
### Cursors ###
|
||||
|
||||
class Cursor(Structure):
|
||||
@ -592,40 +686,209 @@ class _CXUnsavedFile(Structure):
|
||||
_clang_getDiagnostic.restype = c_object_p
|
||||
|
||||
_clang_disposeDiagnostic = lib.clang_disposeDiagnostic
|
||||
_clang_disposeDiagnostic.argtypes = [c_object_p]
|
||||
_clang_disposeDiagnostic.argtypes = [Diagnostic]
|
||||
|
||||
_clang_getDiagnosticSeverity = lib.clang_getDiagnosticSeverity
|
||||
_clang_getDiagnosticSeverity.argtypes = [c_object_p]
|
||||
_clang_getDiagnosticSeverity.argtypes = [Diagnostic]
|
||||
_clang_getDiagnosticSeverity.restype = c_int
|
||||
|
||||
_clang_getDiagnosticLocation = lib.clang_getDiagnosticLocation
|
||||
_clang_getDiagnosticLocation.argtypes = [c_object_p]
|
||||
_clang_getDiagnosticLocation.argtypes = [Diagnostic]
|
||||
_clang_getDiagnosticLocation.restype = SourceLocation
|
||||
|
||||
_clang_getDiagnosticSpelling = lib.clang_getDiagnosticSpelling
|
||||
_clang_getDiagnosticSpelling.argtypes = [c_object_p]
|
||||
_clang_getDiagnosticSpelling.argtypes = [Diagnostic]
|
||||
_clang_getDiagnosticSpelling.restype = _CXString
|
||||
_clang_getDiagnosticSpelling.errcheck = _CXString.from_result
|
||||
|
||||
_clang_getDiagnosticNumRanges = lib.clang_getDiagnosticNumRanges
|
||||
_clang_getDiagnosticNumRanges.argtypes = [c_object_p]
|
||||
_clang_getDiagnosticNumRanges.argtypes = [Diagnostic]
|
||||
_clang_getDiagnosticNumRanges.restype = c_uint
|
||||
|
||||
_clang_getDiagnosticRange = lib.clang_getDiagnosticRange
|
||||
_clang_getDiagnosticRange.argtypes = [c_object_p, c_uint]
|
||||
_clang_getDiagnosticRange.argtypes = [Diagnostic, c_uint]
|
||||
_clang_getDiagnosticRange.restype = SourceRange
|
||||
|
||||
_clang_getDiagnosticNumFixIts = lib.clang_getDiagnosticNumFixIts
|
||||
_clang_getDiagnosticNumFixIts.argtypes = [c_object_p]
|
||||
_clang_getDiagnosticNumFixIts.argtypes = [Diagnostic]
|
||||
_clang_getDiagnosticNumFixIts.restype = c_uint
|
||||
|
||||
_clang_getDiagnosticFixIt = lib.clang_getDiagnosticFixIt
|
||||
_clang_getDiagnosticFixIt.argtypes = [c_object_p, c_uint, POINTER(SourceRange)]
|
||||
_clang_getDiagnosticFixIt.argtypes = [Diagnostic, c_uint, POINTER(SourceRange)]
|
||||
_clang_getDiagnosticFixIt.restype = _CXString
|
||||
_clang_getDiagnosticFixIt.errcheck = _CXString.from_result
|
||||
|
||||
###
|
||||
|
||||
class CompletionChunk:
|
||||
class Kind:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return "<ChunkKind: %s>" % self
|
||||
|
||||
def __init__(self, completionString, key):
|
||||
self.cs = completionString
|
||||
self.key = key
|
||||
|
||||
def __repr__(self):
|
||||
return "{'" + self.spelling + "', " + str(self.kind) + "}"
|
||||
|
||||
@property
|
||||
def spelling(self):
|
||||
return _clang_getCompletionChunkText(self.cs, self.key).spelling
|
||||
|
||||
@property
|
||||
def kind(self):
|
||||
res = _clang_getCompletionChunkKind(self.cs, self.key)
|
||||
return completionChunkKindMap[res]
|
||||
|
||||
@property
|
||||
def string(self):
|
||||
res = _clang_getCompletionChunkCompletionString(self.cs, self.key)
|
||||
|
||||
if (res):
|
||||
return CompletionString(res)
|
||||
else:
|
||||
None
|
||||
|
||||
def isKindOptional(self):
|
||||
return self.kind == completionChunkKindMap[0]
|
||||
|
||||
def isKindTypedText(self):
|
||||
return self.kind == completionChunkKindMap[1]
|
||||
|
||||
def isKindPlaceHolder(self):
|
||||
return self.kind == completionChunkKindMap[3]
|
||||
|
||||
def isKindInformative(self):
|
||||
return self.kind == completionChunkKindMap[4]
|
||||
|
||||
def isKindResultType(self):
|
||||
return self.kind == completionChunkKindMap[15]
|
||||
|
||||
completionChunkKindMap = {
|
||||
0: CompletionChunk.Kind("Optional"),
|
||||
1: CompletionChunk.Kind("TypedText"),
|
||||
2: CompletionChunk.Kind("Text"),
|
||||
3: CompletionChunk.Kind("Placeholder"),
|
||||
4: CompletionChunk.Kind("Informative"),
|
||||
5: CompletionChunk.Kind("CurrentParameter"),
|
||||
6: CompletionChunk.Kind("LeftParen"),
|
||||
7: CompletionChunk.Kind("RightParen"),
|
||||
8: CompletionChunk.Kind("LeftBracket"),
|
||||
9: CompletionChunk.Kind("RightBracket"),
|
||||
10: CompletionChunk.Kind("LeftBrace"),
|
||||
11: CompletionChunk.Kind("RightBrace"),
|
||||
12: CompletionChunk.Kind("LeftAngle"),
|
||||
13: CompletionChunk.Kind("RightAngle"),
|
||||
14: CompletionChunk.Kind("Comma"),
|
||||
15: CompletionChunk.Kind("ResultType"),
|
||||
16: CompletionChunk.Kind("Colon"),
|
||||
17: CompletionChunk.Kind("SemiColon"),
|
||||
18: CompletionChunk.Kind("Equal"),
|
||||
19: CompletionChunk.Kind("HorizontalSpace"),
|
||||
20: CompletionChunk.Kind("VerticalSpace")}
|
||||
|
||||
class CompletionString(ClangObject):
|
||||
class Availability:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return "<Availability: %s>" % self
|
||||
|
||||
def __len__(self):
|
||||
return _clang_getNumCompletionChunks(self.obj)
|
||||
|
||||
def __getitem__(self, key):
|
||||
if len(self) <= key:
|
||||
raise IndexError
|
||||
return CompletionChunk(self.obj, key)
|
||||
|
||||
@property
|
||||
def priority(self):
|
||||
return _clang_getCompletionPriority(self.obj)
|
||||
|
||||
@property
|
||||
def availability(self):
|
||||
res = _clang_getCompletionAvailability(self.obj)
|
||||
return availabilityKinds[res]
|
||||
|
||||
def __repr__(self):
|
||||
return " | ".join([str(a) for a in self]) \
|
||||
+ " || Priority: " + str(self.priority) \
|
||||
+ " || Availability: " + str(self.availability)
|
||||
|
||||
availabilityKinds = {
|
||||
0: CompletionChunk.Kind("Available"),
|
||||
1: CompletionChunk.Kind("Deprecated"),
|
||||
2: CompletionChunk.Kind("NotAvailable")}
|
||||
|
||||
class CodeCompletionResult(Structure):
|
||||
_fields_ = [('cursorKind', c_int), ('completionString', c_object_p)]
|
||||
|
||||
def __repr__(self):
|
||||
return str(CompletionString(self.completionString))
|
||||
|
||||
@property
|
||||
def kind(self):
|
||||
return CursorKind.from_id(self.cursorKind)
|
||||
|
||||
@property
|
||||
def string(self):
|
||||
return CompletionString(self.completionString)
|
||||
|
||||
class CCRStructure(Structure):
|
||||
_fields_ = [('results', POINTER(CodeCompletionResult)),
|
||||
('numResults', c_int)]
|
||||
|
||||
def __len__(self):
|
||||
return self.numResults
|
||||
|
||||
def __getitem__(self, key):
|
||||
if len(self) <= key:
|
||||
raise IndexError
|
||||
|
||||
return self.results[key]
|
||||
|
||||
class CodeCompletionResults(ClangObject):
|
||||
def __init__(self, ptr):
|
||||
assert isinstance(ptr, POINTER(CCRStructure)) and ptr
|
||||
self.ptr = self._as_parameter_ = ptr
|
||||
|
||||
def from_param(self):
|
||||
return self._as_parameter_
|
||||
|
||||
def __del__(self):
|
||||
CodeCompletionResults_dispose(self)
|
||||
|
||||
@property
|
||||
def results(self):
|
||||
return self.ptr.contents
|
||||
|
||||
@property
|
||||
def diagnostics(self):
|
||||
class DiagnosticsItr:
|
||||
def __init__(self, ccr):
|
||||
self.ccr= ccr
|
||||
|
||||
def __len__(self):
|
||||
return int(_clang_codeCompleteGetNumDiagnostics(self.ccr))
|
||||
|
||||
def __getitem__(self, key):
|
||||
return _clang_codeCompleteGetDiagnostic(self.ccr, key)
|
||||
|
||||
return DiagnosticsItr(self)
|
||||
|
||||
|
||||
class Index(ClangObject):
|
||||
"""
|
||||
The Index type provides the primary interface to the Clang CIndex library,
|
||||
@ -650,7 +913,7 @@ def read(self, path):
|
||||
ptr = TranslationUnit_read(self, path)
|
||||
return TranslationUnit(ptr) if ptr else None
|
||||
|
||||
def parse(self, path, args = [], unsaved_files = []):
|
||||
def parse(self, path, args = [], unsaved_files = [], options = 0):
|
||||
"""
|
||||
Load the translation unit from the given source code file by running
|
||||
clang and generating the AST before loading. Additional command line
|
||||
@ -678,8 +941,9 @@ def parse(self, path, args = [], unsaved_files = []):
|
||||
unsaved_files_array[i].name = name
|
||||
unsaved_files_array[i].contents = value
|
||||
unsaved_files_array[i].length = len(value)
|
||||
ptr = TranslationUnit_parse(self, path, len(args), arg_array,
|
||||
len(unsaved_files), unsaved_files_array)
|
||||
ptr = TranslationUnit_parse(self, path, arg_array, len(args),
|
||||
unsaved_files_array, len(unsaved_files),
|
||||
options)
|
||||
return TranslationUnit(ptr) if ptr else None
|
||||
|
||||
|
||||
@ -744,6 +1008,63 @@ def __getitem__(self, key):
|
||||
|
||||
return DiagIterator(self)
|
||||
|
||||
def reparse(self, unsaved_files = [], options = 0):
|
||||
"""
|
||||
Reparse an already parsed translation unit.
|
||||
|
||||
In-memory contents for files can be provided by passing a list of pairs
|
||||
as unsaved_files, the first items should be the filenames to be mapped
|
||||
and the second should be the contents to be substituted for the
|
||||
file. The contents may be passed as strings or file objects.
|
||||
"""
|
||||
unsaved_files_array = 0
|
||||
if len(unsaved_files):
|
||||
unsaved_files_array = (_CXUnsavedFile * len(unsaved_files))()
|
||||
for i,(name,value) in enumerate(unsaved_files):
|
||||
if not isinstance(value, str):
|
||||
# FIXME: It would be great to support an efficient version
|
||||
# of this, one day.
|
||||
value = value.read()
|
||||
print value
|
||||
if not isinstance(value, str):
|
||||
raise TypeError,'Unexpected unsaved file contents.'
|
||||
unsaved_files_array[i].name = name
|
||||
unsaved_files_array[i].contents = value
|
||||
unsaved_files_array[i].length = len(value)
|
||||
ptr = TranslationUnit_reparse(self, len(unsaved_files),
|
||||
unsaved_files_array,
|
||||
options)
|
||||
def codeComplete(self, path, line, column, unsaved_files = [], options = 0):
|
||||
"""
|
||||
Code complete in this translation unit.
|
||||
|
||||
In-memory contents for files can be provided by passing a list of pairs
|
||||
as unsaved_files, the first items should be the filenames to be mapped
|
||||
and the second should be the contents to be substituted for the
|
||||
file. The contents may be passed as strings or file objects.
|
||||
"""
|
||||
unsaved_files_array = 0
|
||||
if len(unsaved_files):
|
||||
unsaved_files_array = (_CXUnsavedFile * len(unsaved_files))()
|
||||
for i,(name,value) in enumerate(unsaved_files):
|
||||
if not isinstance(value, str):
|
||||
# FIXME: It would be great to support an efficient version
|
||||
# of this, one day.
|
||||
value = value.read()
|
||||
print value
|
||||
if not isinstance(value, str):
|
||||
raise TypeError,'Unexpected unsaved file contents.'
|
||||
unsaved_files_array[i].name = name
|
||||
unsaved_files_array[i].contents = value
|
||||
unsaved_files_array[i].length = len(value)
|
||||
ptr = TranslationUnit_codeComplete(self, path,
|
||||
line, column,
|
||||
unsaved_files_array,
|
||||
len(unsaved_files),
|
||||
options)
|
||||
return CodeCompletionResults(ptr) if ptr else None
|
||||
|
||||
|
||||
class File(ClangObject):
|
||||
"""
|
||||
The File class represents a particular source file that is part of a
|
||||
@ -893,11 +1214,20 @@ def is_input_file(self):
|
||||
TranslationUnit_read.argtypes = [Index, c_char_p]
|
||||
TranslationUnit_read.restype = c_object_p
|
||||
|
||||
TranslationUnit_parse = lib.clang_createTranslationUnitFromSourceFile
|
||||
TranslationUnit_parse.argtypes = [Index, c_char_p, c_int, c_void_p,
|
||||
c_int, c_void_p]
|
||||
TranslationUnit_parse = lib.clang_parseTranslationUnit
|
||||
TranslationUnit_parse.argtypes = [Index, c_char_p, c_void_p,
|
||||
c_int, c_void_p, c_int, c_int]
|
||||
TranslationUnit_parse.restype = c_object_p
|
||||
|
||||
TranslationUnit_reparse = lib.clang_reparseTranslationUnit
|
||||
TranslationUnit_reparse.argtypes = [TranslationUnit, c_int, c_void_p, c_int]
|
||||
TranslationUnit_reparse.restype = c_int
|
||||
|
||||
TranslationUnit_codeComplete = lib.clang_codeCompleteAt
|
||||
TranslationUnit_codeComplete.argtypes = [TranslationUnit, c_char_p, c_int,
|
||||
c_int, c_void_p, c_int, c_int]
|
||||
TranslationUnit_codeComplete.restype = POINTER(CCRStructure)
|
||||
|
||||
TranslationUnit_cursor = lib.clang_getTranslationUnitCursor
|
||||
TranslationUnit_cursor.argtypes = [TranslationUnit]
|
||||
TranslationUnit_cursor.restype = Cursor
|
||||
@ -929,7 +1259,46 @@ def is_input_file(self):
|
||||
File_time.argtypes = [File]
|
||||
File_time.restype = c_uint
|
||||
|
||||
# Code completion
|
||||
|
||||
CodeCompletionResults_dispose = lib.clang_disposeCodeCompleteResults
|
||||
CodeCompletionResults_dispose.argtypes = [CodeCompletionResults]
|
||||
|
||||
_clang_codeCompleteGetNumDiagnostics = lib.clang_codeCompleteGetNumDiagnostics
|
||||
_clang_codeCompleteGetNumDiagnostics.argtypes = [CodeCompletionResults]
|
||||
_clang_codeCompleteGetNumDiagnostics.restype = c_int
|
||||
|
||||
_clang_codeCompleteGetDiagnostic = lib.clang_codeCompleteGetDiagnostic
|
||||
_clang_codeCompleteGetDiagnostic.argtypes = [CodeCompletionResults, c_int]
|
||||
_clang_codeCompleteGetDiagnostic.restype = Diagnostic
|
||||
|
||||
_clang_getCompletionChunkText = lib.clang_getCompletionChunkText
|
||||
_clang_getCompletionChunkText.argtypes = [c_void_p, c_int]
|
||||
_clang_getCompletionChunkText.restype = _CXString
|
||||
|
||||
_clang_getCompletionChunkKind = lib.clang_getCompletionChunkKind
|
||||
_clang_getCompletionChunkKind.argtypes = [c_void_p, c_int]
|
||||
_clang_getCompletionChunkKind.restype = c_int
|
||||
|
||||
_clang_getCompletionChunkCompletionString = lib.clang_getCompletionChunkCompletionString
|
||||
_clang_getCompletionChunkCompletionString.argtypes = [c_void_p, c_int]
|
||||
_clang_getCompletionChunkCompletionString.restype = c_object_p
|
||||
|
||||
_clang_getNumCompletionChunks = lib.clang_getNumCompletionChunks
|
||||
_clang_getNumCompletionChunks.argtypes = [c_void_p]
|
||||
_clang_getNumCompletionChunks.restype = c_int
|
||||
|
||||
_clang_getCompletionAvailability = lib.clang_getCompletionAvailability
|
||||
_clang_getCompletionAvailability.argtypes = [c_void_p]
|
||||
_clang_getCompletionAvailability.restype = c_int
|
||||
|
||||
_clang_getCompletionPriority = lib.clang_getCompletionPriority
|
||||
_clang_getCompletionPriority.argtypes = [c_void_p]
|
||||
_clang_getCompletionPriority.restype = c_int
|
||||
|
||||
|
||||
###
|
||||
|
||||
__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind',
|
||||
'Diagnostic', 'FixIt', 'SourceRange', 'SourceLocation', 'File']
|
||||
'Diagnostic', 'FixIt', 'CodeCompletionResults', 'SourceRange',
|
||||
'SourceLocation', 'File']
|
||||
|
@ -3,8 +3,6 @@
|
||||
def tu_from_source(source):
|
||||
index = Index.create()
|
||||
tu = index.parse('INPUT.c', unsaved_files = [('INPUT.c', source)])
|
||||
# FIXME: Remove the need for this.
|
||||
tu.index = index
|
||||
return tu
|
||||
|
||||
# FIXME: We need support for invalid translation units to test better.
|
||||
@ -46,3 +44,26 @@ def test_diagnostic_fixit():
|
||||
assert tu.diagnostics[0].fixits[0].range.end.line == 1
|
||||
assert tu.diagnostics[0].fixits[0].range.end.column == 30
|
||||
assert tu.diagnostics[0].fixits[0].value == '.f0 = '
|
||||
|
||||
def test_diagnostic_range():
|
||||
index = Index.create()
|
||||
tu = tu_from_source("""void f() { int i = "a" + 1; }""")
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
assert tu.diagnostics[0].location.column == 16
|
||||
assert tu.diagnostics[0].spelling.startswith('incompatible pointer to')
|
||||
assert len(tu.diagnostics[0].fixits) == 0
|
||||
assert len(tu.diagnostics[0].ranges) == 1
|
||||
assert tu.diagnostics[0].ranges[0].start.line == 1
|
||||
assert tu.diagnostics[0].ranges[0].start.column == 20
|
||||
assert tu.diagnostics[0].ranges[0].end.line == 1
|
||||
assert tu.diagnostics[0].ranges[0].end.column == 27
|
||||
try:
|
||||
tu.diagnostics[0].ranges[1].start.line
|
||||
except IndexError:
|
||||
assert True
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
||||
|
@ -25,16 +25,24 @@ def test_parse_arguments():
|
||||
assert spellings[-2] == 'hello'
|
||||
assert spellings[-1] == 'hi'
|
||||
|
||||
def test_reparse_arguments():
|
||||
path = os.path.join(kInputsDir, 'parse_arguments.c')
|
||||
index = Index.create()
|
||||
tu = index.parse(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
|
||||
tu.reparse()
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-2] == 'hello'
|
||||
assert spellings[-1] == 'hi'
|
||||
|
||||
def test_unsaved_files():
|
||||
index = Index.create()
|
||||
# FIXME: Why can't we just use "fake.h" here (instead of /tmp/fake.h)?
|
||||
tu = index.parse('fake.c', unsaved_files = [
|
||||
tu = index.parse('fake.c', ['-I./'], unsaved_files = [
|
||||
('fake.c', """
|
||||
#include "/tmp/fake.h"
|
||||
#include "fake.h"
|
||||
int x;
|
||||
int SOME_DEFINE;
|
||||
"""),
|
||||
('/tmp/fake.h', """
|
||||
('./fake.h', """
|
||||
#define SOME_DEFINE y
|
||||
""")
|
||||
])
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -67,19 +67,21 @@ enum {
|
||||
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
|
||||
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
|
||||
BLOCK_IS_GLOBAL = (1 << 28),
|
||||
BLOCK_HAS_STRET = (1 << 29),
|
||||
BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
|
||||
BLOCK_HAS_SIGNATURE = (1 << 30),
|
||||
};
|
||||
|
||||
In 10.6.ABI the (1<<29) was unconditionally set and ignored by the runtime - it was a transitional marker that did not get deleted after the transition. This bit is now paired with (1<<30), and represented as the pair (3<<30), for the following combinations of valid bit settings, and their meanings.
|
||||
In 10.6.ABI the (1<<29) was usually set and was always ignored by the runtime - it had been a transitional marker that did not get deleted after the transition. This bit is now paired with (1<<30), and represented as the pair (3<<30), for the following combinations of valid bit settings, and their meanings.
|
||||
|
||||
switch (flags & (3<<29)) {
|
||||
case (0<<29): <unused> , error
|
||||
case (0<<29): 10.6.ABI, no signature field available
|
||||
case (1<<29): 10.6.ABI, no signature field available
|
||||
case (2<<29): ABI.2010.3.16, regular calling convention, presence of signature field
|
||||
case (3<<29): ABI.2010.3.16, stret calling convention, presence of signature field,
|
||||
}
|
||||
|
||||
The signature field is not always populated.
|
||||
|
||||
The following discussions are presented as 10.6.ABI otherwise.
|
||||
|
||||
Block literals may occur within functions where the structure is created in stack local memory. They may also appear as initialization expressions for Block variables of global or static local variables.
|
||||
@ -348,7 +350,7 @@ void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
|
||||
and
|
||||
struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
|
||||
.byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
|
||||
.captured_voidBlock=blockA };
|
||||
.captured_voidBlock=blockA )};
|
||||
|
||||
voidBlock.forwarding->captured_voidBlock = blockB;
|
||||
|
||||
@ -422,7 +424,9 @@ A __block variable that is also marked __attribute__((NSObject)) should have byr
|
||||
|
||||
2.3.5 __block escapes
|
||||
|
||||
Because Blocks referencing __block variables may have Block_copy() performed upon them the underlying storage for the variables may move to the heap. In Objective-C Garbage Collection Only compilation environments the heap used is the garbage collected one and no further action is required. Otherwise the compiler must issue a call to potentially release any heap storage for __block variables at all escapes or terminations of their scope.
|
||||
Because Blocks referencing __block variables may have Block_copy() performed upon them the underlying storage for the variables may move to the heap. In Objective-C Garbage Collection Only compilation environments the heap used is the garbage collected one and no further action is required. Otherwise the compiler must issue a call to potentially release any heap storage for __block variables at all escapes or terminations of their scope. The call should be:
|
||||
|
||||
_Block_object_dispose(&_block_byref_xxx, BLOCK_FIELD_IS_BYREF);
|
||||
|
||||
|
||||
2.3.6 Nesting
|
||||
@ -537,9 +541,9 @@ and within the compound statement:
|
||||
|
||||
4.0 C++ Support
|
||||
|
||||
Within a block stack based C++ objects are copied as const copies using the const copy constructor. It is an error if a stack based C++ object is used within a block if it does not have a const copy constructor. In addition both copy and destroy helper routines must be synthesized for the block to support the Block_copy() operation, and the flags work marked with the (1<<26) bit in addition to the (1<<25) bit. The copy helper should call the constructor using appropriate offsets of the variable within the supplied stack based block source and heap based destination for all const constructed copies, and similarly should call the destructor in the destroy routine.
|
||||
Within a block stack based C++ objects are copied into const copies using the copy constructor. It is an error if a stack based C++ object is used within a block if it does not have a copy constructor. In addition both copy and destroy helper routines must be synthesized for the block to support the Block_copy() operation, and the flags work marked with the (1<<26) bit in addition to the (1<<25) bit. The copy helper should call the constructor using appropriate offsets of the variable within the supplied stack based block source and heap based destination for all const constructed copies, and similarly should call the destructor in the destroy routine.
|
||||
|
||||
As an example, suppose a C++ class FOO existed with a const copy constructor. Within a code block a stack version of a FOO object is declared and used within a Block literal expression:
|
||||
As an example, suppose a C++ class FOO existed with a copy constructor. Within a code block a stack version of a FOO object is declared and used within a Block literal expression:
|
||||
|
||||
{
|
||||
FOO foo;
|
||||
@ -562,11 +566,11 @@ void __block_invoke_10(struct __block_literal_10 *_block) {
|
||||
}
|
||||
|
||||
void __block_literal_10(struct __block_literal_10 *dst, struct __block_literal_10 *src) {
|
||||
comp_ctor(&dst->foo, &src->foo);
|
||||
FOO_ctor(&dst->foo, &src->foo);
|
||||
}
|
||||
|
||||
void __block_dispose_10(struct __block_literal_10 *src) {
|
||||
comp_dtor(&src->foo);
|
||||
FOO_dtor(&src->foo);
|
||||
}
|
||||
|
||||
static struct __block_descriptor_10 {
|
||||
@ -594,9 +598,33 @@ and the code would be:
|
||||
}
|
||||
|
||||
|
||||
C++ objects stored in __block storage start out on the stack in a block_byref data structure as do other variables. Such objects (if not const objects) must support a regular copy constructor. The block_byref data structure will have copy and destroy helper routines synthesized by the compiler. The copy helper will have code created to perform the copy constructor based on the initial stack block_byref data structure, and will also set the (1<<26) bit in addition to the (1<<25) bit. The destroy helper will have code to do the destructor on the object stored within the supplied block_byref heap data structure.
|
||||
C++ objects stored in __block storage start out on the stack in a block_byref data structure as do other variables. Such objects (if not const objects) must support a regular copy constructor. The block_byref data structure will have copy and destroy helper routines synthesized by the compiler. The copy helper will have code created to perform the copy constructor based on the initial stack block_byref data structure, and will also set the (1<<26) bit in addition to the (1<<25) bit. The destroy helper will have code to do the destructor on the object stored within the supplied block_byref heap data structure. For example,
|
||||
|
||||
To support member variable and function access the compiler will synthesize a const pointer to a block version of the this pointer.
|
||||
__block FOO blockStorageFoo;
|
||||
|
||||
requires the normal constructor for the embedded blockStorageFoo object
|
||||
|
||||
FOO_ctor(& _block_byref_blockStorageFoo->blockStorageFoo);
|
||||
|
||||
and at scope termination the destructor:
|
||||
|
||||
FOO_dtor(& _block_byref_blockStorageFoo->blockStorageFoo);
|
||||
|
||||
Note that the forwarding indirection is NOT used.
|
||||
|
||||
The compiler would need to generate (if used from a block literal) the following copy/dispose helpers:
|
||||
|
||||
void _block_byref_obj_keep(struct _block_byref_blockStorageFoo *dst, struct _block_byref_blockStorageFoo *src) {
|
||||
FOO_ctor(&dst->blockStorageFoo, &src->blockStorageFoo);
|
||||
}
|
||||
|
||||
void _block_byref_obj_dispose(struct _block_byref_blockStorageFoo *src) {
|
||||
FOO_dtor(&src->blockStorageFoo);
|
||||
}
|
||||
|
||||
for the appropriately named constructor and destructor for the class/struct FOO.
|
||||
|
||||
To support member variable and function access the compiler will synthesize a const pointer to a block version of the "this" pointer.
|
||||
|
||||
5.0 Runtime Helper Functions
|
||||
|
||||
@ -640,31 +668,3 @@ void _Block_object_assign(void *destAddr, const void *object, const int flags);
|
||||
*/
|
||||
void _Block_object_dispose(const void *object, const int flags);
|
||||
|
||||
The following functions have been used and will continue to be supported until new compiler support is complete.
|
||||
|
||||
// Obsolete functions.
|
||||
// Copy helper callback for copying a block imported into a Block
|
||||
// Called by copy_helper helper functions synthesized by the compiler.
|
||||
// The address in the destination block of an imported Block is provided as the first argument
|
||||
// and the value of the existing imported Block is the second.
|
||||
// Use: _Block_object_assign(dest, src, BLOCK_FIELD_IS_BLOCK {| BLOCK_FIELD_IS_WEAK});
|
||||
void _Block_copy_assign(struct Block_basic **dest, const struct Block_basic *src, const int flags);
|
||||
|
||||
// Destroy helper callback for releasing Blocks imported into a Block
|
||||
// Called by dispose_helper helper functions synthesized by the compiler.
|
||||
// The value of the imported Block variable is passed back.
|
||||
// Use: _Block_object_dispose(src, BLOCK_FIELD_IS_BLOCK {| BLOCK_FIELD_IS_WEAK});
|
||||
void _Block_destroy(const struct Block_basic *src, const int flags);
|
||||
|
||||
// Byref data block copy helper callback
|
||||
// Called by block copy helpers when copying __block structures
|
||||
// Use: _Block_object_assign(dest, src, BLOCK_FIELD_IS_BYREF {| BLOCK_FIELD_IS_WEAK});
|
||||
void _Block_byref_assign_copy(struct Block_byref **destp, struct Block_byref *src);
|
||||
|
||||
// Byref data block release helper callback
|
||||
// Called by block release helpers when releasing a Block
|
||||
// Called at escape points in scope where __block variables live (under non-GC-only conditions)
|
||||
// Use: _Block_object_dispose(src, BLOCK_FIELD_IS_BYREF {| BLOCK_FIELD_IS_WEAK});
|
||||
void §(struct Block_byref *shared_struct);
|
||||
|
||||
|
||||
|
@ -25,6 +25,7 @@ td {
|
||||
<li><a href="#Diagnostics">The Diagnostics Subsystem</a></li>
|
||||
<li><a href="#SourceLocation">The SourceLocation and SourceManager
|
||||
classes</a></li>
|
||||
<li><a href="#SourceRange">SourceRange and CharSourceRange</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#libdriver">The Driver Library</a>
|
||||
@ -68,6 +69,11 @@ td {
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="libIndex.html">The Index Library</a></li>
|
||||
<li><a href="#Howtos">Howto guides</a>
|
||||
<ul>
|
||||
<li><a href="#AddingAttributes">How to add an attribute</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@ -145,15 +151,14 @@ diagnostic :).</p>
|
||||
pieces, this section describes them and talks about best practices when adding
|
||||
a new diagnostic.</p>
|
||||
|
||||
<!-- ============================== -->
|
||||
<h4>The Diagnostic*Kinds.def files</h4>
|
||||
<!-- ============================== -->
|
||||
<!-- ============================= -->
|
||||
<h4>The Diagnostic*Kinds.td files</h4>
|
||||
<!-- ============================= -->
|
||||
|
||||
<p>Diagnostics are created by adding an entry to one of the <tt>
|
||||
clang/Basic/Diagnostic*Kinds.def</tt> files, depending on what library will
|
||||
be using it. This file encodes the unique ID of the
|
||||
diagnostic (as an enum, the first argument), the severity of the diagnostic
|
||||
(second argument) and the English translation + format string.</p>
|
||||
clang/Basic/Diagnostic*Kinds.td</tt> files, depending on what library will
|
||||
be using it. From this file, tblgen generates the unique ID of the diagnostic,
|
||||
the severity of the diagnostic and the English translation + format string.</p>
|
||||
|
||||
<p>There is little sanity with the naming of the unique ID's right now. Some
|
||||
start with err_, warn_, ext_ to encode the severity into the name. Since the
|
||||
@ -237,7 +242,7 @@ are some simple format strings:</p>
|
||||
|
||||
<ul>
|
||||
<li>Keep the string short. It should ideally fit in the 80 column limit of the
|
||||
<tt>DiagnosticKinds.def</tt> file. This avoids the diagnostic wrapping when
|
||||
<tt>DiagnosticKinds.td</tt> file. This avoids the diagnostic wrapping when
|
||||
printed, and forces you to think about the important point you are conveying
|
||||
with the diagnostic.</li>
|
||||
<li>Take advantage of location information. The user will be able to see the
|
||||
@ -252,7 +257,7 @@ are some simple format strings:</p>
|
||||
<p>Diagnostics should never take random English strings as arguments: you
|
||||
shouldn't use <tt>"you have a problem with %0"</tt> and pass in things like
|
||||
<tt>"your argument"</tt> or <tt>"your return value"</tt> as arguments. Doing
|
||||
this prevents <a href="translation">translating</a> the Clang diagnostics to
|
||||
this prevents <a href="#translation">translating</a> the Clang diagnostics to
|
||||
other languages (because they'll get random English words in their otherwise
|
||||
localized diagnostic). The exceptions to this are C/C++ language keywords
|
||||
(e.g. auto, const, mutable, etc) and C/C++ operators (<tt>/=</tt>). Note
|
||||
@ -367,10 +372,10 @@ of repetitive diagnostics and/or have an idea for a useful formatter, please
|
||||
bring it up on the cfe-dev mailing list.</p>
|
||||
|
||||
<!-- ===================================================== -->
|
||||
<h4><a name="#producingdiag">Producing the Diagnostic</a></h4>
|
||||
<h4 id="producingdiag">Producing the Diagnostic</h4>
|
||||
<!-- ===================================================== -->
|
||||
|
||||
<p>Now that you've created the diagnostic in the DiagnosticKinds.def file, you
|
||||
<p>Now that you've created the diagnostic in the DiagnosticKinds.td file, you
|
||||
need to write the code that detects the condition in question and emits the
|
||||
new diagnostic. Various components of Clang (e.g. the preprocessor, Sema,
|
||||
etc) provide a helper function named "Diag". It creates a diagnostic and
|
||||
@ -388,7 +393,7 @@ it.</p>
|
||||
|
||||
<p>This shows that use of the Diag method: they take a location (a <a
|
||||
href="#SourceLocation">SourceLocation</a> object) and a diagnostic enum value
|
||||
(which matches the name from DiagnosticKinds.def). If the diagnostic takes
|
||||
(which matches the name from DiagnosticKinds.td). If the diagnostic takes
|
||||
arguments, they are specified with the << operator: the first argument
|
||||
becomes %0, the second becomes %1, etc. The diagnostic interface allows you to
|
||||
specify arguments of many different types, including <tt>int</tt> and
|
||||
@ -545,6 +550,30 @@ die. The reason for this is that the notion of the 'spelling' of a Token in
|
||||
Clang depends on being able to find the original input characters for the token.
|
||||
This concept maps directly to the "spelling location" for the token.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="SourceRange">SourceRange and CharSourceRange</h3>
|
||||
<!-- ======================================================================= -->
|
||||
<!-- mostly taken from
|
||||
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-August/010595.html -->
|
||||
|
||||
<p>Clang represents most source ranges by [first, last], where first and last
|
||||
each point to the beginning of their respective tokens. For example
|
||||
consider the SourceRange of the following statement:</p>
|
||||
<pre>
|
||||
x = foo + bar;
|
||||
^first ^last
|
||||
</pre>
|
||||
|
||||
<p>To map from this representation to a character-based
|
||||
representation, the 'last' location needs to be adjusted to point to
|
||||
(or past) the end of that token with either
|
||||
<code>Lexer::MeasureTokenLength()</code> or
|
||||
<code>Lexer::getLocForEndOfToken()</code>. For the rare cases
|
||||
where character-level source ranges information is needed we use
|
||||
the <code>CharSourceRange</code> class.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libdriver">The Driver Library</h2>
|
||||
<!-- ======================================================================= -->
|
||||
@ -1682,10 +1711,82 @@ interacts with constant evaluation:</p>
|
||||
floating-point literal.</li>
|
||||
<li><b><tt>__builtin_abs,copysign,..</tt></b>: These are constant folded as
|
||||
general constant expressions.</li>
|
||||
<li><b><tt>__builtin_strlen</tt></b> and <b><tt>strlen</tt></b>: These are constant folded as integer constant expressions if the argument is a string literal.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="Howtos">How to change Clang</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="AddingAttributes">How to add an attribute</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>To add an attribute, you'll have to add it to the list of attributes, add it
|
||||
to the parsing phase, and look for it in the AST scan.
|
||||
<a href="http://llvm.org/viewvc/llvm-project?view=rev&revision=124217">r124217</a>
|
||||
has a good example of adding a warning attribute.</p>
|
||||
|
||||
<p>(Beware that this hasn't been reviewed/fixed by the people who designed the
|
||||
attributes system yet.)</p>
|
||||
|
||||
<h4><a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?view=markup">include/clang/Basic/Attr.td</a></h4>
|
||||
|
||||
<p>Each attribute gets a <tt>def</tt> inheriting from <tt>Attr</tt> or one of
|
||||
its subclasses. <tt>InheritableAttr</tt> means that the attribute also applies
|
||||
to subsequent declarations of the same name.</p>
|
||||
|
||||
<p><tt>Spellings</tt> lists the strings that can appear in
|
||||
<tt>__attribute__((here))</tt> or <tt>[[here]]</tt>. All such strings
|
||||
will be synonymous. If you want to allow the <tt>[[]]</tt> C++0x
|
||||
syntax, you have to define a list of <tt>Namespaces</tt>, which will
|
||||
let users write <tt>[[namespace:spelling]]</tt>. Using the empty
|
||||
string for a namespace will allow users to write just the spelling
|
||||
with no "<tt>:</tt>".</p>
|
||||
|
||||
<p><tt>Subjects</tt> restricts what kinds of AST node to which this attribute
|
||||
can appertain (roughly, attach).</p>
|
||||
|
||||
<p><tt>Args</tt> names the arguments the attribute takes, in order. If
|
||||
<tt>Args</tt> is <tt>[StringArgument<"Arg1">, IntArgument<"Arg2">]</tt>
|
||||
then <tt>__attribute__((myattribute("Hello", 3)))</tt> will be a valid use.</p>
|
||||
|
||||
<h4>Boilerplate</h4>
|
||||
|
||||
<p>Add an element to the <tt>AttributeList::Kind</tt> enum in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?view=markup">include/clang/Sema/AttributeList.h</a>
|
||||
named <tt>AT_lower_with_underscores</tt>. That is, a CamelCased
|
||||
<tt>AttributeName</tt> in <tt>Attr.td</tt> name should become
|
||||
<tt>AT_attribute_name</tt>.</p>
|
||||
|
||||
<p>Add a case to the <tt>StringSwitch</tt> in <tt>AttributeList::getKind()</tt>
|
||||
in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?view=markup">lib/Sema/AttributeList.cpp</a>
|
||||
for each spelling of your attribute. Less common attributes should come toward
|
||||
the end of that list.</p>
|
||||
|
||||
<p>Write a new <tt>HandleYourAttr()</tt> function in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?view=markup">lib/Sema/SemaDeclAttr.cpp</a>,
|
||||
and add a case to the switch in <tt>ProcessNonInheritableDeclAttr()</tt> or
|
||||
<tt>ProcessInheritableDeclAttr()</tt> forwarding to it.</p>
|
||||
|
||||
<p>If your attribute causes extra warnings to fire, define a <tt>DiagGroup</tt>
|
||||
in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?view=markup">include/clang/Basic/DiagnosticGroups.td</a>
|
||||
named after the attribute's <tt>Spelling</tt> with "_"s replaced by "-"s. If
|
||||
you're only defining one diagnostic, you can skip <tt>DiagnosticGroups.td</tt>
|
||||
and use <tt>InGroup<DiagGroup<"your-attribute">></tt> directly in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?view=markup">DiagnosticSemaKinds.td</a></p>
|
||||
|
||||
<h4>The meat of your attribute</h4>
|
||||
|
||||
<p>Find an appropriate place in Clang to do whatever your attribute needs to do.
|
||||
Check for the attribute's presence using <tt>Decl::getAttr<YourAttr>()</tt>.</p>
|
||||
|
||||
<p>Update the <a href="LanguageExtensions.html">Clang Language Extensions</a>
|
||||
document to describe your new attribute.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
@ -23,6 +23,8 @@ td {
|
||||
<li><a href="#has_include">Include File Checking Macros</a></li>
|
||||
<li><a href="#builtinmacros">Builtin Macros</a></li>
|
||||
<li><a href="#vectors">Vectors and Extended Vectors</a></li>
|
||||
<li><a href="#deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> attributes</a></li>
|
||||
<li><a href="#attributes-on-enumerators">Attributes on enumerators</a></li>
|
||||
<li><a href="#checking_language_features">Checks for Standard Language Features</a></li>
|
||||
<ul>
|
||||
<li><a href="#cxx_exceptions">C++ exceptions</a></li>
|
||||
@ -32,23 +34,27 @@ td {
|
||||
<ul>
|
||||
<li><a href="#cxx_attributes">C++0x attributes</a></li>
|
||||
<li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
|
||||
<li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
|
||||
<li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
|
||||
<li><a href="#cxx_concepts">C++ TR concepts</a></li>
|
||||
<li><a href="#cxx_lambdas">C++0x lambdas</a></li>
|
||||
<li><a href="#cxx_nullptr">C++0x nullptr</a></li>
|
||||
<li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
|
||||
<li><a href="#cxx_reference_qualified_functions">C++0x reference-qualified functions</a></li>
|
||||
<li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
|
||||
<li><a href="#cxx_auto_type">C++0x type inference</a></li>
|
||||
<li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
|
||||
<li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
|
||||
<li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
|
||||
<li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
|
||||
</ul>
|
||||
<li><a href="#checking_type_traits">Checks for Type Traits</a></li>
|
||||
<li><a href="#blocks">Blocks</a></li>
|
||||
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
|
||||
<li><a href="#builtins">Builtin Functions</a>
|
||||
<ul>
|
||||
<li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
|
||||
<li><a href="#__builtin_unreachable">__builtin_unreachable</a></li>
|
||||
</ul>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#targetspecific">Target-Specific Extensions</a>
|
||||
<ul>
|
||||
@ -132,6 +138,30 @@ can be used like this:</p>
|
||||
|
||||
<p>The feature tag is described along with the language feature below.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="__has_attribute">__has_attribute</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This function-like macro takes a single identifier argument that is the name
|
||||
of an attribute. It evaluates to 1 if the attribute is supported or 0 if not. It
|
||||
can be used like this:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#ifndef __has_attribute // Optional of course.
|
||||
#define __has_attribute(x) 0 // Compatibility with non-clang compilers.
|
||||
#endif
|
||||
|
||||
...
|
||||
#if __has_attribute(always_inline)
|
||||
#define ALWAYS_INLINE __attribute__((always_inline))
|
||||
#else
|
||||
#define ALWAYS_INLINE
|
||||
#endif
|
||||
...
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="has_include">Include File Checking Macros</h2>
|
||||
<!-- ======================================================================= -->
|
||||
@ -259,12 +289,60 @@ float4 foo(float2 a, float2 b) {
|
||||
c.yw = b;
|
||||
return c;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Query for this feature with __has_feature(attribute_ext_vector_type).</p>
|
||||
|
||||
<p>See also <a href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> Attributes</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>An optional string message can be added to the <tt>deprecated</tt>
|
||||
and <tt>unavailable</tt> attributes. For example:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>void explode(void) __attribute__((deprecated("extremely unsafe, use 'combust' instead!!!")));</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>If the deprecated or unavailable declaration is used, the message
|
||||
will be incorporated into the appropriate diagnostic:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>harmless.c:4:3: warning: 'explode' is deprecated: extremely unsafe, use 'combust' instead!!! [-Wdeprecated-declarations]
|
||||
explode();
|
||||
^</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Query for this feature
|
||||
with <tt>__has_feature(attribute_deprecated_with_message)</tt>
|
||||
and <tt>__has_feature(attribute_unavailable_with_message)</tt>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="attributes-on-enumerators">Attributes on Enumerators</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang allows attributes to be written on individual enumerators.
|
||||
This allows enumerators to be deprecated, made unavailable, etc. The
|
||||
attribute must appear after the enumerator name and before any
|
||||
initializer, like so:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>enum OperationMode {
|
||||
OM_Invalid,
|
||||
OM_Normal,
|
||||
OM_Terrified __attribute__((deprecated)),
|
||||
OM_AbortOnError __attribute__((deprecated)) = 4
|
||||
};</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Attributes on the <tt>enum</tt> declaration do not apply to
|
||||
individual enumerators.</p>
|
||||
|
||||
<p>Query for this feature with <tt>__has_feature(enumerator_attributes)</tt>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="checking_language_features">Checks for Standard Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
@ -304,16 +382,15 @@ not yet implemented will be noted.</p>
|
||||
<p>Use <tt>__has_feature(cxx_attributes)</tt> to determine if support for
|
||||
attribute parsing with C++0x's square bracket notation is enabled.</p>
|
||||
|
||||
<h3 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> to determine if support for default template arguments in function templates is enabled.</p>
|
||||
|
||||
<h3 id="cxx_deleted_functions">C++0x deleted functions</tt></h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> to determine if support for
|
||||
deleted function definitions (with <tt>= delete</tt>) is enabled.</p>
|
||||
|
||||
<h3 id="cxx_concepts">C++ TR concepts</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_concepts)</tt> to determine if support for
|
||||
concepts is enabled. clang does not currently implement this feature.</p>
|
||||
|
||||
<h3 id="cxx_lambdas">C++0x lambdas</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_lambdas)</tt> to determine if support for
|
||||
@ -325,11 +402,13 @@ lambdas is enabled. clang does not currently implement this feature.</p>
|
||||
<tt>nullptr</tt> is enabled. clang does not yet fully implement this
|
||||
feature.</p>
|
||||
|
||||
<h3 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h3>
|
||||
<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> to determine if support for reference-qualified functions (e.g., member functions with <code>&</code> or <code>&&</code> applied to <code>*this</code>) is enabled.</p>
|
||||
|
||||
<h3 id="cxx_rvalue_references">C++0x rvalue references</tt></h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> to determine if support for
|
||||
rvalue references is enabled. clang does not yet fully implement this
|
||||
feature.</p>
|
||||
rvalue references is enabled. </p>
|
||||
|
||||
<h3 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h3>
|
||||
|
||||
@ -340,19 +419,69 @@ compile-time assertions using <tt>static_assert</tt> is enabled.</p>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_auto_type)</tt> to determine C++0x type inference
|
||||
is supported using the <tt>auto</tt> specifier. If this is disabled,
|
||||
<tt>auto</tt> will instead be a storage class specifier, as in C or C++98.</p>
|
||||
<tt>auto</tt> will instead be a storage class specifier, as in C or C++98.
|
||||
Clang does not currently implement this feature.</p>
|
||||
|
||||
<h3 id="cxx_variadic_templates">C++0x variadic templates</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> to determine if support
|
||||
for templates taking any number of arguments with the ellipsis notation is
|
||||
enabled. clang does not yet fully implement this feature.</p>
|
||||
for variadic templates is enabled.</p>
|
||||
|
||||
<h3 id="cxx_inline_namespaces">C++0x inline namespaces</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> to determine if support for
|
||||
inline namespaces is enabled.</p>
|
||||
|
||||
<h3 id="cxx_trailing_return">C++0x trailing return type</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_trailing_return)</tt> to determine if support for
|
||||
the alternate function declaration syntax with trailing return type is enabled.</p>
|
||||
|
||||
<h3 id="cxx_strong_enums">C++0x strongly typed enumerations</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_strong_enums)</tt> to determine if support for
|
||||
strongly typed, scoped enumerations is enabled.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="checking_type_traits">Checks for Type Traits</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang supports the <a hef="http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html">GNU C++ type traits</a> and a subset of the <a href="http://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx">Microsoft Visual C++ Type traits</a>. For each supported type trait <code>__X</code>, <code>__has_feature(X)</code> indicates the presence of the type trait. For example:
|
||||
<blockquote>
|
||||
<pre>
|
||||
#if __has_feature(is_convertible_to)
|
||||
template<typename From, typename To>
|
||||
struct is_convertible_to {
|
||||
static const bool value = __is_convertible_to(From, To);
|
||||
};
|
||||
#else
|
||||
// Emulate type trait
|
||||
#endif
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>The following type traits are supported by Clang:</p>
|
||||
<ul>
|
||||
<li><code>__has_nothrow_assign</code> (GNU, Microsoft)</li>
|
||||
<li><code>__has_nothrow_copy</code> (GNU, Microsoft)</li>
|
||||
<li><code>__has_nothrow_constructor</code> (GNU, Microsoft)</li>
|
||||
<li><code>__has_trivial_assign</code> (GNU, Microsoft)</li>
|
||||
<li><code>__has_trivial_copy</code> (GNU, Microsoft)</li>
|
||||
<li><code>__has_trivial_constructor</code> (GNU, Microsoft)</li>
|
||||
<li><code>__has_trivial_destructor</code> (GNU, Microsoft)</li>
|
||||
<li><code>__has_virtual_destructor</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_abstract</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_base_of</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_class</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_convertible_to</code> (Microsoft)</li>
|
||||
<li><code>__is_empty</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_enum</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_pod</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_polymorphic</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_union</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_literal(type)</code>: Determines whether the given type is a literal type</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="blocks">Blocks</h2>
|
||||
<!-- ======================================================================= -->
|
||||
@ -445,7 +574,7 @@ void honeypot(...) __attribute__((overloadable, unavailable)); <i>// calling me
|
||||
their names mangled according to the same rules as C++ function
|
||||
names. For example, the three <tt>tgsin</tt> functions in our
|
||||
motivating example get the mangled names <tt>_Z5tgsinf</tt>,
|
||||
<tt>_Z5tgsind</tt>, and <tt>Z5tgsine</tt>, respectively. There are two
|
||||
<tt>_Z5tgsind</tt>, and <tt>_Z5tgsine</tt>, respectively. There are two
|
||||
caveats to this use of name mangling:</p>
|
||||
|
||||
<ul>
|
||||
@ -660,6 +789,51 @@ placed at the end of function prototypes:</p>
|
||||
|
||||
<p>Query for this feature with __has_feature(attribute_analyzer_noreturn).</p>
|
||||
|
||||
<h4 id="attr_retain_release">Objective-C retaining behavior attributes</h4>
|
||||
|
||||
<p>In Objective-C, functions and methods are generally assumed to take
|
||||
and return objects with +0 retain counts, with some exceptions for
|
||||
special methods like <tt>+alloc</tt> and <tt>init</tt>. However,
|
||||
there are exceptions, and so Clang provides attributes to allow these
|
||||
exceptions to be documented, which helps the analyzer find leaks (and
|
||||
ignore non-leaks).</p>
|
||||
|
||||
<p><b>Usage</b>: The <tt>ns_returns_retained</tt>, <tt>ns_returns_not_retained</tt>,
|
||||
<tt>ns_returns_autoreleased</tt>, <tt>cf_returns_retained</tt>,
|
||||
and <tt>cf_returns_not_retained</tt> attributes can be placed on
|
||||
methods and functions that return Objective-C or CoreFoundation
|
||||
objects. They are commonly placed at the end of a function prototype
|
||||
or method declaration:</p>
|
||||
|
||||
<pre>
|
||||
id foo() <b>__attribute__((ns_returns_retained))</b>;
|
||||
|
||||
- (NSString*) bar: (int) x <b>__attribute__((ns_returns_retained))</b>;
|
||||
</pre>
|
||||
|
||||
<p>The <tt>*_returns_retained</tt> attributes specify that the
|
||||
returned object has a +1 retain count.
|
||||
The <tt>*_returns_not_retained</tt> attributes specify that the return
|
||||
object has a +0 retain count, even if the normal convention for its
|
||||
selector would be +1. <tt>ns_returns_autoreleased</tt> specifies that the
|
||||
returned object is +0, but is guaranteed to live at least as long as the
|
||||
next flush of an autorelease pool.</p>
|
||||
|
||||
<p><b>Usage</b>: The <tt>ns_consumed</tt> and <tt>cf_consumed</tt>
|
||||
attributes can be placed on an parameter declaration; they specify
|
||||
that the argument is expected to have a +1 retain count, which will be
|
||||
balanced in some way by the function or method.
|
||||
The <tt>ns_consumes_self</tt> attribute can only be placed on an
|
||||
Objective-C method; it specifies that the method expects
|
||||
its <tt>self</tt> parameter to have a +1 retain count, which it will
|
||||
balance in some way.</p>
|
||||
|
||||
<pre>
|
||||
void <b>foo(__attribute__((ns_consumed))</b> NSString *string);
|
||||
|
||||
- (void) bar <b>__attribute__((ns_consumes_self))</b>;
|
||||
- (void) baz: (id) <b>__attribute__((ns_consumed))</b> x;
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
@ -59,7 +59,7 @@ $(PROJ_OBJ_DIR)/html.tar.gz: $(HTML)
|
||||
$(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/html.tar
|
||||
$(Verb) cd $(PROJ_SRC_DIR) && \
|
||||
$(TAR) cf $(PROJ_OBJ_DIR)/html.tar *.html
|
||||
$(Verb) $(GZIP) $(PROJ_OBJ_DIR)/html.tar
|
||||
$(Verb) $(GZIPBIN) $(PROJ_OBJ_DIR)/html.tar
|
||||
|
||||
install-doxygen: doxygen
|
||||
$(Echo) Installing doxygen documentation
|
||||
@ -82,7 +82,7 @@ $(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg
|
||||
$(Echo) Packaging doxygen documentation
|
||||
$(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/doxygen.tar
|
||||
$(Verb) $(TAR) cf $(PROJ_OBJ_DIR)/doxygen.tar doxygen
|
||||
$(Verb) $(GZIP) $(PROJ_OBJ_DIR)/doxygen.tar
|
||||
$(Verb) $(GZIPBIN) $(PROJ_OBJ_DIR)/doxygen.tar
|
||||
$(Verb) $(CP) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(PROJ_OBJ_DIR)/doxygen/html/
|
||||
|
||||
userloc: $(LLVM_SRC_ROOT)/docs/userloc.html
|
||||
|
@ -391,23 +391,23 @@ precompiled header, which contains the serialized representation of
|
||||
that statement or expression. Each substatement or subexpression
|
||||
within an expression is stored as a separate record (which keeps most
|
||||
records to a fixed size). Within the precompiled header, the
|
||||
subexpressions of an expression are stored prior to the expression
|
||||
subexpressions of an expression are stored, in reverse order, prior to the expression
|
||||
that owns those expression, using a form of <a
|
||||
href="http://en.wikipedia.org/wiki/Reverse_Polish_notation">Reverse
|
||||
Polish Notation</a>. For example, an expression <code>3 - 4 + 5</code>
|
||||
would be represented as follows:</p>
|
||||
|
||||
<table border="1">
|
||||
<tr><td><code>IntegerLiteral(3)</code></td></tr>
|
||||
<tr><td><code>IntegerLiteral(4)</code></td></tr>
|
||||
<tr><td><code>BinaryOperator(-)</code></td></tr>
|
||||
<tr><td><code>IntegerLiteral(5)</code></td></tr>
|
||||
<tr><td><code>IntegerLiteral(4)</code></td></tr>
|
||||
<tr><td><code>IntegerLiteral(3)</code></td></tr>
|
||||
<tr><td><code>BinaryOperator(-)</code></td></tr>
|
||||
<tr><td><code>BinaryOperator(+)</code></td></tr>
|
||||
<tr><td>STOP</td></tr>
|
||||
</table>
|
||||
|
||||
<p>When reading this representation, Clang evaluates each expression
|
||||
record it encounters, builds the appropriate abstract synax tree node,
|
||||
record it encounters, builds the appropriate abstract syntax tree node,
|
||||
and then pushes that expression on to a stack. When a record contains <i>N</i>
|
||||
subexpressions--<code>BinaryOperator</code> has two of them--those
|
||||
expressions are popped from the top of the stack. The special STOP
|
||||
|
@ -248,32 +248,29 @@ when this is enabled, Clang will print something like:</p>
|
||||
^
|
||||
//
|
||||
</pre>
|
||||
|
||||
<p>When this is disabled, Clang will just print:</p>
|
||||
|
||||
<pre>
|
||||
<b><font color="black">test.c:28:8: <font color="magenta">warning</font>: extra tokens at end of #endif directive [-Wextra-tokens]</font></b>
|
||||
#endif bad
|
||||
<font color="green">^</font>
|
||||
<font color="green">//</font>
|
||||
</pre>
|
||||
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fcolor_diagnostics"><b>-f[no-]color-diagnostics</b>: </dt>
|
||||
<dd>This option, which defaults to on when a color-capable terminal is
|
||||
detected, controls whether or not Clang prints diagnostics in color.
|
||||
When this option is enabled, Clang will use colors to highlight
|
||||
specific parts of the diagnostic, e.g.,
|
||||
|
||||
<pre>
|
||||
<test.c:2:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
#endif bad
|
||||
^
|
||||
//
|
||||
<pre>
|
||||
<b><font color="black">test.c:28:8: <font color="magenta">warning</font>: extra tokens at end of #endif directive [-Wextra-tokens]</font></b>
|
||||
#endif bad
|
||||
<font color="green">^</font>
|
||||
<font color="green">//</font>
|
||||
</pre>
|
||||
</dd>'
|
||||
|
||||
<p>When this is disabled, Clang will just print:</p>
|
||||
|
||||
<pre>
|
||||
test.c:2:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
#endif bad
|
||||
^
|
||||
//
|
||||
</pre>
|
||||
</dd>
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-show-option"><b>-f[no-]diagnostics-show-option</b>:
|
||||
Enable <tt>[-Woption]</tt> information in diagnostic line.</dt>
|
||||
@ -565,7 +562,7 @@ example code will tell Clang or GCC to ignore the -Wall warnings:</p>
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
</pre>
|
||||
|
||||
<p>In addition to all of the functionality of provided by GCC's pragma, Clang
|
||||
<p>In addition to all of the functionality provided by GCC's pragma, Clang
|
||||
also allows you to push and pop the current warning state. This is particularly
|
||||
useful when writing a header file that will be compiled by other people, because
|
||||
you don't know what warning flags they build with.</p>
|
||||
@ -604,7 +601,7 @@ by the user via changes to the source code. This can be done in two ways:
|
||||
attributes (e.g., <tt>__attribute__((nonnull)))</tt>) that can either suppress
|
||||
static analyzer warnings or teach the analyzer about code invariants which
|
||||
enable it to find more bugs. While many of these attributes are standard GCC
|
||||
attributes, additional ones have added to Clang to specifically support the
|
||||
attributes, additional ones have been added to Clang to specifically support the
|
||||
static analyzer. Detailed information on these annotations can be found in the
|
||||
<a href="http://clang-analyzer.llvm.org/annotations.html">analyzer's
|
||||
documentation</a>.</li>
|
||||
@ -623,7 +620,7 @@ selectively exclude code the analyzer examines. Here is an example:
|
||||
In general, this usage is discouraged. Instead, we prefer that users file bugs
|
||||
against the analyzer when it flags false positives. There is also active
|
||||
discussion of allowing users in the future to selectively silence specific
|
||||
analyzer warnings (some which can already be done using <a
|
||||
analyzer warnings (some of which can already be done using <a
|
||||
href="analyzer_annotations">annotations</a>).</li>
|
||||
|
||||
</ul>
|
||||
@ -642,7 +639,7 @@ Precompiled header files, which represent one of many ways to implement
|
||||
this optimization, are literally files that represent an on-disk cache that
|
||||
contains the vital information necessary to reduce some of the work
|
||||
needed to process a corresponding header file. While details of precompiled
|
||||
headers vary between compilers, precompiled headers have been shown to be a
|
||||
headers vary between compilers, precompiled headers have been shown to be
|
||||
highly effective at speeding up program compilation on systems with very large
|
||||
system headers (e.g., Mac OS/X).</p>
|
||||
|
||||
@ -742,11 +739,11 @@ likely to affect PCH files that reference a large number of headers.</p>
|
||||
on runtime code generation to check for undefined behavior.</dt>
|
||||
|
||||
<dd>This option, which defaults to off, controls whether or not Clang
|
||||
adds runtime checks for undefined runtime behavior. If the check fails,
|
||||
adds runtime checks for undefined runtime behavior. If a check fails,
|
||||
<tt>__builtin_trap()</tt> is used to indicate failure.
|
||||
The checks are:
|
||||
<p>
|
||||
<li>Subscripting where the static type of one operand is variable
|
||||
<li>Subscripting where the static type of one operand is a variable
|
||||
which is decayed from an array type and the other operand is
|
||||
greater than the size of the array or less than zero.</li>
|
||||
<li>Shift operators where the amount shifted is greater or equal to the
|
||||
@ -761,7 +758,7 @@ The checks are:
|
||||
<dt id="opt_fno-assume-sane-operator-new"><b>-fno-assume-sane-operator-new</b>:
|
||||
Don't assume that the C++'s new operator is sane.</dt>
|
||||
<dd>This option tells the compiler to do not assume that C++'s global new
|
||||
operator will always return a pointer that do not
|
||||
operator will always return a pointer that does not
|
||||
alias any other pointer when the function returns.</dd>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
@ -828,10 +825,6 @@ c94 mode (FIXME: And __STDC_VERSION__ should be defined!).</p>
|
||||
extensions are not implemented yet:</p>
|
||||
|
||||
<ul>
|
||||
<li>clang does not support __label__
|
||||
(<a href="http://llvm.org/bugs/show_bug.cgi?id=3429">bug 3429</a>). This is
|
||||
a relatively small feature, so it is likely to be implemented relatively
|
||||
soon.</li>
|
||||
|
||||
<li>clang does not support #pragma weak
|
||||
(<a href="http://llvm.org/bugs/show_bug.cgi?id=3679">bug 3679</a>). Due to
|
||||
@ -887,9 +880,11 @@ bug-reporting guidelines somewhere?).</p>
|
||||
<ul>
|
||||
|
||||
<li>clang does not support the gcc extension that allows variable-length arrays
|
||||
in structures. This is for a few of reasons: one, it is tricky
|
||||
in structures. This is for a few reasons: one, it is tricky
|
||||
to implement, two, the extension is completely undocumented, and three, the
|
||||
extension appears to be rarely used.</li>
|
||||
extension appears to be rarely used. Note that clang <em>does</em> support
|
||||
flexible array members (arrays with a zero or unspecified size at the end of
|
||||
a structure).</li>
|
||||
|
||||
<li>clang does not support duplicate definitions of a function where one is
|
||||
inline. This complicates clients of the AST which normally can expect there is
|
||||
@ -922,6 +917,12 @@ support is incomplete; enabling Microsoft extensions will silently drop
|
||||
certain constructs (including __declspec and Microsoft-style asm statements).
|
||||
</p>
|
||||
|
||||
<li>clang allows setting _MSC_VER with -fmsc-version=. It defaults to 1300 which
|
||||
is the same as Visual C/C++ 2003. Any number is supported and can greatly affect
|
||||
what Windows SDK and c++stdlib headers clang can compile. This option will be
|
||||
removed when clang supports the full set of MS extensions required for these
|
||||
headers.</li>
|
||||
|
||||
<li>clang does not support the Microsoft extension where anonymous
|
||||
record members can be declared using user defined typedefs.</li>
|
||||
|
||||
@ -942,16 +943,19 @@ definition.</li>
|
||||
<!-- ======================== -->
|
||||
<h4 id="target_arch_x86">X86</h4>
|
||||
<!-- ======================== -->
|
||||
<p>The support for X86 (both 32-bit and 64-bit) is considered stable
|
||||
on Darwin (Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested to
|
||||
correctly compile large C and Objective-C codebases. (FIXME: Anything specific
|
||||
we want to say here? Possibly mention some LLVM x86 limitations?)
|
||||
|
||||
<p>The support for X86 (both 32-bit and 64-bit) is considered stable on Darwin
|
||||
(Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested to correctly
|
||||
compile many large C, C++, Objective-C, and Objective-C++ codebases.</p>
|
||||
|
||||
<!-- ======================== -->
|
||||
<h4 id="target_arch_arm">ARM</h4>
|
||||
<!-- ======================== -->
|
||||
ARM support is mostly feature-complete, but still experimental; it hasn't
|
||||
undergone significant testing.
|
||||
|
||||
<p>The support for ARM (specifically ARMv6 and ARMv7) is considered stable on
|
||||
Darwin (iOS): it has been tested to correctly compile many large C, C++,
|
||||
Objective-C, and Objective-C++ codebases. Clang only supports a limited number
|
||||
of ARM architectures. It does not yet fully support ARMv5, for example.</p>
|
||||
|
||||
<!-- ======================== -->
|
||||
<h4 id="target_arch_other">Other platforms</h4>
|
||||
@ -960,9 +964,6 @@ clang currently contains some support for PPC and Sparc; however, significant
|
||||
pieces of code generation are still missing, and they haven't undergone
|
||||
significant testing.
|
||||
|
||||
<p>clang contains some support for the embedded PIC16 processor
|
||||
(FIXME: I haven't been keeping track of this; what should this say?).
|
||||
|
||||
<p>clang contains limited support for the MSP430 embedded processor, but both
|
||||
the clang support and the LLVM backend support are highly experimental.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
=head1 NAME
|
||||
|
||||
clang - the Clang C and Objective-C compiler
|
||||
clang - the Clang C, C++, and Objective-C compiler
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@ -14,11 +14,12 @@ B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
|
||||
B<-f>I<feature-option...>
|
||||
B<-m>I<machine-option...>
|
||||
B<-o> I<output-file>
|
||||
B<-stdlib=>I<library>
|
||||
I<input-filenames>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<clang> is a C and Objective-C compiler which encompasses preprocessing,
|
||||
B<clang> is a C, C++, and Objective-C compiler which encompasses preprocessing,
|
||||
parsing, optimization, code generation, assembly, and linking. Depending on
|
||||
which high-level mode setting is passed, Clang will stop before doing a full
|
||||
link. While Clang is highly integrated, it is important to understand the
|
||||
@ -37,7 +38,8 @@ the other tools.
|
||||
|
||||
This stage handles tokenization of the input source file, macro expansion,
|
||||
#include expansion and handling of other preprocessor directives. The output of
|
||||
this stage is typically called a ".i" (for C) or ".mi" (for Objective-C) file.
|
||||
this stage is typically called a ".i" (for C), ".ii" (for C++), ".mi" (for
|
||||
Objective-C) , or ".mii" (for Objective-C++) file.
|
||||
|
||||
=item B<Parsing and Semantic Analysis>
|
||||
|
||||
@ -78,7 +80,7 @@ stages. In addition to compilation of code, Clang also supports other tools:
|
||||
B<Clang Static Analyzer>
|
||||
|
||||
The Clang Static Analyzer is a tool that scans source code to try to find bugs
|
||||
though code analysis. This tool uses many parts of Clang and is built into the
|
||||
through code analysis. This tool uses many parts of Clang and is built into the
|
||||
same driver.
|
||||
|
||||
|
||||
@ -130,6 +132,11 @@ Treat subsequent input files as having type I<language>.
|
||||
|
||||
Specify the language standard to compile for.
|
||||
|
||||
=item B<-stdlib>=I<language>
|
||||
|
||||
Specify the C++ standard library to use; supported options are libstdc++ and
|
||||
libc++.
|
||||
|
||||
=item B<-ansi>
|
||||
|
||||
Same as B<-std=c89>.
|
||||
@ -168,6 +175,10 @@ Enable support for Pascal-style strings with "\pfoo".
|
||||
|
||||
Enable support for Microsoft extensions.
|
||||
|
||||
=item B<-fmsc-version=>
|
||||
|
||||
Set _MSC_VER. Defaults to 1300 on Windows. Not set otherwise.
|
||||
|
||||
=item B<-fborland-extensions>
|
||||
|
||||
Enable support for Borland extensions.
|
||||
@ -185,7 +196,6 @@ Allow loose type checking rules for implicit vector conversions.
|
||||
|
||||
Enable the "Blocks" language feature.
|
||||
|
||||
|
||||
=item B<-fobjc-gc-only>
|
||||
|
||||
Indicate that Objective-C code should be compiled in GC-only mode, which only
|
||||
@ -196,6 +206,22 @@ works when Objective-C Garbage Collection is enabled.
|
||||
Indicate that Objective-C code should be compiled in hybrid-GC mode, which works
|
||||
with both GC and non-GC mode.
|
||||
|
||||
=item B<-fobjc-abi-version>=I<version>
|
||||
|
||||
Select the Objective-C ABI version to use. Available versions are 1 (legacy
|
||||
"fragile" ABI), 2 (non-fragile ABI 1), and 3 (non-fragile ABI 2).
|
||||
|
||||
=item B<-fobjc-nonfragile-abi-version>=I<version>
|
||||
|
||||
Select the Objective-C non-fragile ABI version to use by default. This will only
|
||||
be used as the Objective-C ABI when the non-fragile ABI is enabled (either via
|
||||
-fobjc-nonfragile-abi, or because it is the platform default).
|
||||
|
||||
=item B<-fobjc-nonfragile-abi>
|
||||
|
||||
Enable use of the Objective-C non-fragile ABI. On platforms for which this is
|
||||
the default ABI, it can be disabled with B<-fno-objc-nonfragile-abi>.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
@ -1,6 +1,11 @@
|
||||
set(MODULE TRUE)
|
||||
|
||||
set(LLVM_NO_RTTI 1)
|
||||
set( LLVM_USED_LIBS
|
||||
clangFrontend
|
||||
clangAST
|
||||
)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS support mc)
|
||||
|
||||
add_clang_library(PrintFunctionNames PrintFunctionNames.cpp)
|
||||
|
||||
|
@ -18,7 +18,11 @@ EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/PrintFunctionNames.exports
|
||||
endif
|
||||
endif
|
||||
|
||||
LINK_LIBS_IN_SHARED = 1
|
||||
LINK_LIBS_IN_SHARED = 0
|
||||
SHARED_LIBRARY = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
ifeq ($(OS),Darwin)
|
||||
LDFLAGS=-Wl,-undefined,dynamic_lookup
|
||||
endif
|
||||
|
@ -1,10 +1,12 @@
|
||||
This is a simple example demonstrating how to use clang's facility for
|
||||
providing AST consumers using a plugin.
|
||||
|
||||
You will probably need to build clang so that it exports all symbols (disable
|
||||
TOOL_NO_EXPORT in the tools/clang Makefile).
|
||||
Build the plugin by running `make` in this directory.
|
||||
|
||||
Once the plugin is built, you can run it using:
|
||||
--
|
||||
$ clang -cc1 -load path/to/PrintFunctionNames.so -plugin print-fns some-input-file.c
|
||||
--
|
||||
Linux:
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns some-input-file.c
|
||||
|
||||
Mac:
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns some-input-file.c
|
||||
|
@ -1,12 +1,12 @@
|
||||
set(LLVM_NO_RTTI 1)
|
||||
|
||||
set(LLVM_USED_LIBS
|
||||
clangFrontend
|
||||
clangSerialization
|
||||
clangDriver
|
||||
clangCodeGen
|
||||
clangSema
|
||||
clangChecker
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangIndex
|
||||
clangAnalysis
|
||||
clangRewrite
|
||||
|
@ -18,7 +18,7 @@ TOOL_NO_EXPORTS = 1
|
||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
||||
selectiondag asmparser
|
||||
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
|
||||
clangSema.a clangChecker.a clangAnalysis.a clangRewrite.a \
|
||||
clangSema.a clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangAnalysis.a clangRewrite.a \
|
||||
clangAST.a clangParse.a clangLex.a clangBasic.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
@ -17,7 +17,6 @@
|
||||
#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"
|
||||
@ -26,12 +25,17 @@
|
||||
#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/Support/Host.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Target/TargetSelect.h"
|
||||
using namespace clang;
|
||||
using namespace clang::driver;
|
||||
|
||||
// This function isn't referenced outside its translation unit, but it
|
||||
// can't use the "static" keyword because its address is used for
|
||||
// GetMainExecutable (since some platforms don't support taking the
|
||||
// address of main, and some platforms can't implement GetMainExecutable
|
||||
// without being given the address of a function in the main executable).
|
||||
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.
|
||||
@ -39,7 +43,7 @@ llvm::sys::Path GetExecutablePath(const char *Argv0) {
|
||||
return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
|
||||
}
|
||||
|
||||
int Execute(llvm::Module *Mod, char * const *envp) {
|
||||
static int Execute(llvm::Module *Mod, char * const *envp) {
|
||||
llvm::InitializeNativeTarget();
|
||||
|
||||
std::string Error;
|
||||
@ -69,7 +73,8 @@ int main(int argc, const char **argv, char * const *envp) {
|
||||
TextDiagnosticPrinter *DiagClient =
|
||||
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
|
||||
|
||||
Diagnostic Diags(DiagClient);
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
Diagnostic Diags(DiagID, DiagClient);
|
||||
Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
|
||||
"a.out", /*IsProduction=*/false, /*CXXIsProduction=*/false,
|
||||
Diags);
|
||||
@ -124,7 +129,6 @@ int main(int argc, const char **argv, char * const *envp) {
|
||||
|
||||
// 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.
|
||||
|
@ -1,5 +1,3 @@
|
||||
set(LLVM_NO_RTTI 1)
|
||||
|
||||
set(LLVM_USED_LIBS
|
||||
clangIndex
|
||||
clangFrontend
|
||||
@ -7,7 +5,9 @@ set(LLVM_USED_LIBS
|
||||
clangSema
|
||||
clangAnalysis
|
||||
clangSerialization
|
||||
clangChecker
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangRewrite
|
||||
clangAST
|
||||
clangParse
|
||||
|
@ -16,7 +16,7 @@ NO_INSTALL = 1
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
LINK_COMPONENTS := asmparser bitreader mc core
|
||||
USEDLIBS = clangChecker.a clangIndex.a clangFrontend.a clangDriver.a \
|
||||
USEDLIBS = clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangIndex.a clangFrontend.a clangDriver.a \
|
||||
clangSema.a clangAnalysis.a clangSerialization.a \
|
||||
clangAST.a clangParse.a clangLex.a clangBasic.a
|
||||
|
||||
|
@ -14,10 +14,12 @@
|
||||
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Checker/PathSensitive/AnalysisManager.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/Checker/Checkers/LocalCheckers.h"
|
||||
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Index/CallGraph.h"
|
||||
@ -26,6 +28,7 @@
|
||||
#include "clang/Index/DeclReferenceMap.h"
|
||||
#include "clang/Index/SelectorMap.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -91,7 +94,9 @@ int main(int argc, char **argv) {
|
||||
= CompilerInstance::createDiagnostics(DiagOpts, argc, argv);
|
||||
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
|
||||
const std::string &InFile = InputFilenames[i];
|
||||
llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromASTFile(InFile, Diags));
|
||||
llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromASTFile(InFile, Diags,
|
||||
FileSystemOptions(),
|
||||
false, 0, 0, true));
|
||||
if (!AST)
|
||||
return 1;
|
||||
|
||||
@ -129,20 +134,45 @@ int main(int argc, char **argv) {
|
||||
// Create an analysis engine.
|
||||
Preprocessor &PP = TU->getPreprocessor();
|
||||
|
||||
// Hard code options for now.
|
||||
AnalyzerOptions Opts;
|
||||
|
||||
// Hard code options and checkers for now.
|
||||
|
||||
Opts.MaxNodes = 300000;
|
||||
Opts.MaxLoop = 3;
|
||||
Opts.InlineCall = true;
|
||||
Opts.CFGAddImplicitDtors = true;
|
||||
Opts.EagerlyTrimEGraph = true;
|
||||
|
||||
Opts.CheckersControlList.push_back(std::make_pair("core", true));
|
||||
if (PP.getTargetInfo().getTriple().getOS() != llvm::Triple::Win32)
|
||||
Opts.CheckersControlList.push_back(std::make_pair("unix", true));
|
||||
if (PP.getTargetInfo().getTriple().getVendor() == llvm::Triple::Apple)
|
||||
Opts.CheckersControlList.push_back(std::make_pair("macosx", true));
|
||||
|
||||
// Checks to perform for Objective-C/Objective-C++.
|
||||
if (PP.getLangOptions().ObjC1)
|
||||
Opts.CheckersControlList.push_back(std::make_pair("cocoa", true));
|
||||
|
||||
llvm::OwningPtr<ento::CheckerManager> checkerMgr;
|
||||
checkerMgr.reset(ento::registerCheckers(Opts, PP.getDiagnostics()));
|
||||
|
||||
using namespace clang::ento;
|
||||
AnalysisManager AMgr(TU->getASTContext(), PP.getDiagnostics(),
|
||||
PP.getLangOptions(), /* PathDiagnostic */ 0,
|
||||
CreateRegionStoreManager,
|
||||
CreateRangeConstraintManager, &Idxer,
|
||||
/* MaxNodes */ 300000, /* MaxLoop */ 3,
|
||||
/* VisualizeEG */ false, /* VisualizeEGUbi */ false,
|
||||
/* PurgeDead */ true, /* EagerlyAssume */ false,
|
||||
/* TrimGraph */ false, /* InlineCall */ true,
|
||||
/* UseUnoptimizedCFG */ false);
|
||||
CreateRangeConstraintManager, checkerMgr.get(), &Idxer,
|
||||
Opts.MaxNodes, Opts.MaxLoop,
|
||||
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
|
||||
Opts.PurgeDead, Opts.EagerlyAssume,
|
||||
Opts.TrimGraph, Opts.InlineCall,
|
||||
Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
|
||||
Opts.CFGAddInitializers,
|
||||
Opts.EagerlyTrimEGraph);
|
||||
|
||||
GRTransferFuncs* TF = MakeCFRefCountTF(AMgr.getASTContext(), /*GC*/false,
|
||||
TransferFuncs* TF = MakeCFRefCountTF(AMgr.getASTContext(), /*GC*/false,
|
||||
AMgr.getLangOptions());
|
||||
GRExprEngine Eng(AMgr, TF);
|
||||
ExprEngine Eng(AMgr, TF);
|
||||
|
||||
Eng.ExecuteWorkList(AMgr.getStackFrame(FD, TU), AMgr.getMaxNodes());
|
||||
|
||||
|
@ -63,7 +63,7 @@ typedef void *CXIndex;
|
||||
/**
|
||||
* \brief A single translation unit, which resides in an index.
|
||||
*/
|
||||
typedef void *CXTranslationUnit; /* A translation unit instance. */
|
||||
typedef struct CXTranslationUnitImpl *CXTranslationUnit;
|
||||
|
||||
/**
|
||||
* \brief Opaque pointer representing client data that will be passed through
|
||||
@ -133,10 +133,8 @@ enum CXAvailabilityKind {
|
||||
* with the string data, call \c clang_disposeString() to free the string.
|
||||
*/
|
||||
typedef struct {
|
||||
const char *Spelling;
|
||||
/* A 1 value indicates the clang_ indexing API needed to allocate the string
|
||||
(and it must be freed by clang_disposeString()). */
|
||||
int MustFreeString;
|
||||
void *data;
|
||||
unsigned private_flags;
|
||||
} CXString;
|
||||
|
||||
/**
|
||||
@ -201,18 +199,6 @@ CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_disposeIndex(CXIndex index);
|
||||
|
||||
/**
|
||||
* \brief Request that AST's be generated externally for API calls which parse
|
||||
* source code on the fly, e.g. \see createTranslationUnitFromSourceFile.
|
||||
*
|
||||
* Note: This is for debugging purposes only, and may be removed at a later
|
||||
* date.
|
||||
*
|
||||
* \param index - The index to update.
|
||||
* \param value - The new flag value.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_setUseExternalASTGeneration(CXIndex index,
|
||||
int value);
|
||||
/**
|
||||
* \defgroup CINDEX_FILES File manipulation routines
|
||||
*
|
||||
@ -269,8 +255,8 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
|
||||
* \brief Identifies a specific source location within a translation
|
||||
* unit.
|
||||
*
|
||||
* Use clang_getInstantiationLocation() to map a source location to a
|
||||
* particular file, line, and column.
|
||||
* Use clang_getInstantiationLocation() or clang_getSpellingLocation()
|
||||
* to map a source location to a particular file, line, and column.
|
||||
*/
|
||||
typedef struct {
|
||||
void *ptr_data[2];
|
||||
@ -313,6 +299,13 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu,
|
||||
CXFile file,
|
||||
unsigned line,
|
||||
unsigned column);
|
||||
/**
|
||||
* \brief Retrieves the source location associated with a given character offset
|
||||
* in a particular translation unit.
|
||||
*/
|
||||
CINDEX_LINKAGE CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
|
||||
CXFile file,
|
||||
unsigned offset);
|
||||
|
||||
/**
|
||||
* \brief Retrieve a NULL (invalid) source range.
|
||||
@ -330,6 +323,9 @@ CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin,
|
||||
* \brief Retrieve the file, line, column, and offset represented by
|
||||
* the given source location.
|
||||
*
|
||||
* If the location refers into a macro instantiation, retrieves the
|
||||
* location of the macro instantiation.
|
||||
*
|
||||
* \param location the location within a source file that will be decomposed
|
||||
* into its parts.
|
||||
*
|
||||
@ -351,6 +347,34 @@ CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location,
|
||||
unsigned *column,
|
||||
unsigned *offset);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the file, line, column, and offset represented by
|
||||
* the given source location.
|
||||
*
|
||||
* If the location refers into a macro instantiation, return where the
|
||||
* location was originally spelled in the source file.
|
||||
*
|
||||
* \param location the location within a source file that will be decomposed
|
||||
* into its parts.
|
||||
*
|
||||
* \param file [out] if non-NULL, will be set to the file to which the given
|
||||
* source location points.
|
||||
*
|
||||
* \param line [out] if non-NULL, will be set to the line to which the given
|
||||
* source location points.
|
||||
*
|
||||
* \param column [out] if non-NULL, will be set to the column to which the given
|
||||
* source location points.
|
||||
*
|
||||
* \param offset [out] if non-NULL, will be set to the offset into the
|
||||
* buffer to which the given source location points.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_getSpellingLocation(CXSourceLocation location,
|
||||
CXFile *file,
|
||||
unsigned *line,
|
||||
unsigned *column,
|
||||
unsigned *offset);
|
||||
|
||||
/**
|
||||
* \brief Retrieve a source location representing the first character within a
|
||||
* source range.
|
||||
@ -475,7 +499,34 @@ enum CXDiagnosticDisplayOptions {
|
||||
* This option corresponds to the clang flag
|
||||
* \c -fdiagnostics-print-source-range-info.
|
||||
*/
|
||||
CXDiagnostic_DisplaySourceRanges = 0x04
|
||||
CXDiagnostic_DisplaySourceRanges = 0x04,
|
||||
|
||||
/**
|
||||
* \brief Display the option name associated with this diagnostic, if any.
|
||||
*
|
||||
* The option name displayed (e.g., -Wconversion) will be placed in brackets
|
||||
* after the diagnostic text. This option corresponds to the clang flag
|
||||
* \c -fdiagnostics-show-option.
|
||||
*/
|
||||
CXDiagnostic_DisplayOption = 0x08,
|
||||
|
||||
/**
|
||||
* \brief Display the category number associated with this diagnostic, if any.
|
||||
*
|
||||
* The category number is displayed within brackets after the diagnostic text.
|
||||
* This option corresponds to the clang flag
|
||||
* \c -fdiagnostics-show-category=id.
|
||||
*/
|
||||
CXDiagnostic_DisplayCategoryId = 0x10,
|
||||
|
||||
/**
|
||||
* \brief Display the category name associated with this diagnostic, if any.
|
||||
*
|
||||
* The category name is displayed within brackets after the diagnostic text.
|
||||
* This option corresponds to the clang flag
|
||||
* \c -fdiagnostics-show-category=name.
|
||||
*/
|
||||
CXDiagnostic_DisplayCategoryName = 0x20
|
||||
};
|
||||
|
||||
/**
|
||||
@ -505,10 +556,6 @@ CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic,
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void);
|
||||
|
||||
/**
|
||||
* \brief Print a diagnostic to the given file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Determine the severity of the given diagnostic.
|
||||
*/
|
||||
@ -528,6 +575,43 @@ CINDEX_LINKAGE CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic);
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_getDiagnosticSpelling(CXDiagnostic);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the name of the command-line option that enabled this
|
||||
* diagnostic.
|
||||
*
|
||||
* \param Diag The diagnostic to be queried.
|
||||
*
|
||||
* \param Disable If non-NULL, will be set to the option that disables this
|
||||
* diagnostic (if any).
|
||||
*
|
||||
* \returns A string that contains the command-line option used to enable this
|
||||
* warning, such as "-Wconversion" or "-pedantic".
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_getDiagnosticOption(CXDiagnostic Diag,
|
||||
CXString *Disable);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the category number for this diagnostic.
|
||||
*
|
||||
* Diagnostics can be categorized into groups along with other, related
|
||||
* diagnostics (e.g., diagnostics under the same warning flag). This routine
|
||||
* retrieves the category number for the given diagnostic.
|
||||
*
|
||||
* \returns The number of the category that contains this diagnostic, or zero
|
||||
* if this diagnostic is uncategorized.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_getDiagnosticCategory(CXDiagnostic);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the name of a particular diagnostic category.
|
||||
*
|
||||
* \param Category A diagnostic category number, as returned by
|
||||
* \c clang_getDiagnosticCategory().
|
||||
*
|
||||
* \returns The name of the given diagnostic category.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_getDiagnosticCategoryName(unsigned Category);
|
||||
|
||||
/**
|
||||
* \brief Determine the number of source ranges associated with the given
|
||||
* diagnostic.
|
||||
@ -621,9 +705,20 @@ clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
|
||||
* '-fsyntax-only'
|
||||
* '-o <output file>' (both '-o' and '<output file>' are ignored)
|
||||
*
|
||||
* \param CIdx The index object with which the translation unit will be
|
||||
* associated.
|
||||
*
|
||||
* \param source_filename - The name of the source file to load, or NULL if the
|
||||
* source file is included in clang_command_line_args.
|
||||
* source file is included in \p clang_command_line_args.
|
||||
*
|
||||
* \param num_clang_command_line_args The number of command-line arguments in
|
||||
* \p clang_command_line_args.
|
||||
*
|
||||
* \param clang_command_line_args The command-line arguments that would be
|
||||
* passed to the \c clang executable if it were being invoked out-of-process.
|
||||
* These command-line options will be parsed and will affect how the translation
|
||||
* unit is parsed. Note that the following options are ignored: '-c',
|
||||
* '-emit-ast', '-fsyntex-only' (which is the default), and '-o <output file>'.
|
||||
*
|
||||
* \param num_unsaved_files the number of unsaved file entries in \p
|
||||
* unsaved_files.
|
||||
@ -633,13 +728,6 @@ clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
|
||||
* those files. The contents and name of these files (as specified by
|
||||
* CXUnsavedFile) are copied when necessary, so the client only needs to
|
||||
* guarantee their validity until the call to this function returns.
|
||||
*
|
||||
* \param diag_callback callback function that will receive any diagnostics
|
||||
* emitted while processing this source file. If NULL, diagnostics will be
|
||||
* suppressed.
|
||||
*
|
||||
* \param diag_client_data client data that will be passed to the diagnostic
|
||||
* callback function.
|
||||
*/
|
||||
CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile(
|
||||
CXIndex CIdx,
|
||||
@ -718,7 +806,22 @@ enum CXTranslationUnit_Flags {
|
||||
* introduces some overhead to reparsing but improves the performance of
|
||||
* code-completion operations.
|
||||
*/
|
||||
CXTranslationUnit_CacheCompletionResults = 0x08
|
||||
CXTranslationUnit_CacheCompletionResults = 0x08,
|
||||
/**
|
||||
* \brief Enable precompiled preambles in C++.
|
||||
*
|
||||
* Note: this is a *temporary* option that is available only while
|
||||
* we are testing C++ precompiled preamble support.
|
||||
*/
|
||||
CXTranslationUnit_CXXPrecompiledPreamble = 0x10,
|
||||
|
||||
/**
|
||||
* \brief Enabled chained precompiled preambles in C++.
|
||||
*
|
||||
* Note: this is a *temporary* option that is available only while
|
||||
* we are testing C++ precompiled preamble support.
|
||||
*/
|
||||
CXTranslationUnit_CXXChainedPCH = 0x20
|
||||
};
|
||||
|
||||
/**
|
||||
@ -749,7 +852,7 @@ CINDEX_LINKAGE unsigned clang_defaultEditingTranslationUnitOptions(void);
|
||||
* associated.
|
||||
*
|
||||
* \param source_filename The name of the source file to load, or NULL if the
|
||||
* source file is included in \p clang_command_line_args.
|
||||
* source file is included in \p command_line_args.
|
||||
*
|
||||
* \param command_line_args The command-line arguments that would be
|
||||
* passed to the \c clang executable if it were being invoked out-of-process.
|
||||
@ -1000,7 +1103,6 @@ enum CXCursorKind {
|
||||
CXCursor_UsingDirective = 34,
|
||||
/** \brief A using declaration. */
|
||||
CXCursor_UsingDeclaration = 35,
|
||||
|
||||
CXCursor_FirstDecl = CXCursor_UnexposedDecl,
|
||||
CXCursor_LastDecl = CXCursor_UsingDeclaration,
|
||||
|
||||
@ -1027,15 +1129,75 @@ enum CXCursorKind {
|
||||
CXCursor_TypeRef = 43,
|
||||
CXCursor_CXXBaseSpecifier = 44,
|
||||
/**
|
||||
* \brief A reference to a class template, function template, or template
|
||||
* template parameter.
|
||||
* \brief A reference to a class template, function template, template
|
||||
* template parameter, or class template partial specialization.
|
||||
*/
|
||||
CXCursor_TemplateRef = 45,
|
||||
/**
|
||||
* \brief A reference to a namespace or namespace alias.
|
||||
*/
|
||||
CXCursor_NamespaceRef = 46,
|
||||
CXCursor_LastRef = CXCursor_NamespaceRef,
|
||||
/**
|
||||
* \brief A reference to a member of a struct, union, or class that occurs in
|
||||
* some non-expression context, e.g., a designated initializer.
|
||||
*/
|
||||
CXCursor_MemberRef = 47,
|
||||
/**
|
||||
* \brief A reference to a labeled statement.
|
||||
*
|
||||
* This cursor kind is used to describe the jump to "start_over" in the
|
||||
* goto statement in the following example:
|
||||
*
|
||||
* \code
|
||||
* start_over:
|
||||
* ++counter;
|
||||
*
|
||||
* goto start_over;
|
||||
* \endcode
|
||||
*
|
||||
* A label reference cursor refers to a label statement.
|
||||
*/
|
||||
CXCursor_LabelRef = 48,
|
||||
|
||||
/**
|
||||
* \brief A reference to a set of overloaded functions or function templates
|
||||
* that has not yet been resolved to a specific function or function template.
|
||||
*
|
||||
* An overloaded declaration reference cursor occurs in C++ templates where
|
||||
* a dependent name refers to a function. For example:
|
||||
*
|
||||
* \code
|
||||
* template<typename T> void swap(T&, T&);
|
||||
*
|
||||
* struct X { ... };
|
||||
* void swap(X&, X&);
|
||||
*
|
||||
* template<typename T>
|
||||
* void reverse(T* first, T* last) {
|
||||
* while (first < last - 1) {
|
||||
* swap(*first, *--last);
|
||||
* ++first;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* struct Y { };
|
||||
* void swap(Y&, Y&);
|
||||
* \endcode
|
||||
*
|
||||
* Here, the identifier "swap" is associated with an overloaded declaration
|
||||
* reference. In the template definition, "swap" refers to either of the two
|
||||
* "swap" functions declared above, so both results will be available. At
|
||||
* instantiation time, "swap" may also refer to other functions found via
|
||||
* argument-dependent lookup (e.g., the "swap" function at the end of the
|
||||
* example).
|
||||
*
|
||||
* The functions \c clang_getNumOverloadedDecls() and
|
||||
* \c clang_getOverloadedDecl() can be used to retrieve the definitions
|
||||
* referenced by this cursor.
|
||||
*/
|
||||
CXCursor_OverloadedDeclRef = 49,
|
||||
|
||||
CXCursor_LastRef = CXCursor_OverloadedDeclRef,
|
||||
|
||||
/* Error conditions */
|
||||
CXCursor_FirstInvalid = 70,
|
||||
@ -1095,7 +1257,21 @@ enum CXCursorKind {
|
||||
* reported.
|
||||
*/
|
||||
CXCursor_UnexposedStmt = 200,
|
||||
CXCursor_LastStmt = 200,
|
||||
|
||||
/** \brief A labelled statement in a function.
|
||||
*
|
||||
* This cursor kind is used to describe the "start_over:" label statement in
|
||||
* the following example:
|
||||
*
|
||||
* \code
|
||||
* start_over:
|
||||
* ++counter;
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
CXCursor_LabelStmt = 201,
|
||||
|
||||
CXCursor_LastStmt = CXCursor_LabelStmt,
|
||||
|
||||
/**
|
||||
* \brief Cursor that represents the translation unit itself.
|
||||
@ -1122,8 +1298,9 @@ enum CXCursorKind {
|
||||
CXCursor_PreprocessingDirective = 500,
|
||||
CXCursor_MacroDefinition = 501,
|
||||
CXCursor_MacroInstantiation = 502,
|
||||
CXCursor_InclusionDirective = 503,
|
||||
CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective,
|
||||
CXCursor_LastPreprocessing = CXCursor_MacroInstantiation
|
||||
CXCursor_LastPreprocessing = CXCursor_InclusionDirective
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1173,6 +1350,11 @@ CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor);
|
||||
|
||||
/**
|
||||
* \brief Compute a hash value for the given cursor.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_hashCursor(CXCursor);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the kind of the given cursor.
|
||||
*/
|
||||
@ -1278,6 +1460,167 @@ CINDEX_LINKAGE enum CXLanguageKind {
|
||||
*/
|
||||
CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor);
|
||||
|
||||
|
||||
/**
|
||||
* \brief A fast container representing a set of CXCursors.
|
||||
*/
|
||||
typedef struct CXCursorSetImpl *CXCursorSet;
|
||||
|
||||
/**
|
||||
* \brief Creates an empty CXCursorSet.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCursorSet clang_createCXCursorSet();
|
||||
|
||||
/**
|
||||
* \brief Disposes a CXCursorSet and releases its associated memory.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_disposeCXCursorSet(CXCursorSet cset);
|
||||
|
||||
/**
|
||||
* \brief Queries a CXCursorSet to see if it contains a specific CXCursor.
|
||||
*
|
||||
* \returns non-zero if the set contains the specified cursor.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_CXCursorSet_contains(CXCursorSet cset,
|
||||
CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Inserts a CXCursor into a CXCursorSet.
|
||||
*
|
||||
* \returns zero if the CXCursor was already in the set, and non-zero otherwise.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_CXCursorSet_insert(CXCursorSet cset,
|
||||
CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Determine the semantic parent of the given cursor.
|
||||
*
|
||||
* The semantic parent of a cursor is the cursor that semantically contains
|
||||
* the given \p cursor. For many declarations, the lexical and semantic parents
|
||||
* are equivalent (the lexical parent is returned by
|
||||
* \c clang_getCursorLexicalParent()). They diverge when declarations or
|
||||
* definitions are provided out-of-line. For example:
|
||||
*
|
||||
* \code
|
||||
* class C {
|
||||
* void f();
|
||||
* };
|
||||
*
|
||||
* void C::f() { }
|
||||
* \endcode
|
||||
*
|
||||
* In the out-of-line definition of \c C::f, the semantic parent is the
|
||||
* the class \c C, of which this function is a member. The lexical parent is
|
||||
* the place where the declaration actually occurs in the source code; in this
|
||||
* case, the definition occurs in the translation unit. In general, the
|
||||
* lexical parent for a given entity can change without affecting the semantics
|
||||
* of the program, and the lexical parent of different declarations of the
|
||||
* same entity may be different. Changing the semantic parent of a declaration,
|
||||
* on the other hand, can have a major impact on semantics, and redeclarations
|
||||
* of a particular entity should all have the same semantic context.
|
||||
*
|
||||
* In the example above, both declarations of \c C::f have \c C as their
|
||||
* semantic context, while the lexical context of the first \c C::f is \c C
|
||||
* and the lexical context of the second \c C::f is the translation unit.
|
||||
*
|
||||
* For global declarations, the semantic parent is the translation unit.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCursor clang_getCursorSemanticParent(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Determine the lexical parent of the given cursor.
|
||||
*
|
||||
* The lexical parent of a cursor is the cursor in which the given \p cursor
|
||||
* was actually written. For many declarations, the lexical and semantic parents
|
||||
* are equivalent (the semantic parent is returned by
|
||||
* \c clang_getCursorSemanticParent()). They diverge when declarations or
|
||||
* definitions are provided out-of-line. For example:
|
||||
*
|
||||
* \code
|
||||
* class C {
|
||||
* void f();
|
||||
* };
|
||||
*
|
||||
* void C::f() { }
|
||||
* \endcode
|
||||
*
|
||||
* In the out-of-line definition of \c C::f, the semantic parent is the
|
||||
* the class \c C, of which this function is a member. The lexical parent is
|
||||
* the place where the declaration actually occurs in the source code; in this
|
||||
* case, the definition occurs in the translation unit. In general, the
|
||||
* lexical parent for a given entity can change without affecting the semantics
|
||||
* of the program, and the lexical parent of different declarations of the
|
||||
* same entity may be different. Changing the semantic parent of a declaration,
|
||||
* on the other hand, can have a major impact on semantics, and redeclarations
|
||||
* of a particular entity should all have the same semantic context.
|
||||
*
|
||||
* In the example above, both declarations of \c C::f have \c C as their
|
||||
* semantic context, while the lexical context of the first \c C::f is \c C
|
||||
* and the lexical context of the second \c C::f is the translation unit.
|
||||
*
|
||||
* For declarations written in the global scope, the lexical parent is
|
||||
* the translation unit.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCursor clang_getCursorLexicalParent(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Determine the set of methods that are overridden by the given
|
||||
* method.
|
||||
*
|
||||
* In both Objective-C and C++, a method (aka virtual member function,
|
||||
* in C++) can override a virtual method in a base class. For
|
||||
* Objective-C, a method is said to override any method in the class's
|
||||
* interface (if we're coming from an implementation), its protocols,
|
||||
* or its categories, that has the same selector and is of the same
|
||||
* kind (class or instance). If no such method exists, the search
|
||||
* continues to the class's superclass, its protocols, and its
|
||||
* categories, and so on.
|
||||
*
|
||||
* For C++, a virtual member function overrides any virtual member
|
||||
* function with the same signature that occurs in its base
|
||||
* classes. With multiple inheritance, a virtual member function can
|
||||
* override several virtual member functions coming from different
|
||||
* base classes.
|
||||
*
|
||||
* In all cases, this function determines the immediate overridden
|
||||
* method, rather than all of the overridden methods. For example, if
|
||||
* a method is originally declared in a class A, then overridden in B
|
||||
* (which in inherits from A) and also in C (which inherited from B),
|
||||
* then the only overridden method returned from this function when
|
||||
* invoked on C's method will be B's method. The client may then
|
||||
* invoke this function again, given the previously-found overridden
|
||||
* methods, to map out the complete method-override set.
|
||||
*
|
||||
* \param cursor A cursor representing an Objective-C or C++
|
||||
* method. This routine will compute the set of methods that this
|
||||
* method overrides.
|
||||
*
|
||||
* \param overridden A pointer whose pointee will be replaced with a
|
||||
* pointer to an array of cursors, representing the set of overridden
|
||||
* methods. If there are no overridden methods, the pointee will be
|
||||
* set to NULL. The pointee must be freed via a call to
|
||||
* \c clang_disposeOverriddenCursors().
|
||||
*
|
||||
* \param num_overridden A pointer to the number of overridden
|
||||
* functions, will be set to the number of overridden functions in the
|
||||
* array pointed to by \p overridden.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_getOverriddenCursors(CXCursor cursor,
|
||||
CXCursor **overridden,
|
||||
unsigned *num_overridden);
|
||||
|
||||
/**
|
||||
* \brief Free the set of overridden cursors returned by \c
|
||||
* clang_getOverriddenCursors().
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_disposeOverriddenCursors(CXCursor *overridden);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the file that is included by the given inclusion directive
|
||||
* cursor.
|
||||
*/
|
||||
CINDEX_LINKAGE CXFile clang_getIncludedFile(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -1438,6 +1781,24 @@ CINDEX_LINKAGE unsigned clang_equalTypes(CXType A, CXType B);
|
||||
*/
|
||||
CINDEX_LINKAGE CXType clang_getCanonicalType(CXType T);
|
||||
|
||||
/**
|
||||
* \determine Determine whether a CXType has the "const" qualifier set,
|
||||
* without looking through typedefs that may have added "const" at a different level.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_isConstQualifiedType(CXType T);
|
||||
|
||||
/**
|
||||
* \determine Determine whether a CXType has the "volatile" qualifier set,
|
||||
* without looking through typedefs that may have added "volatile" at a different level.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_isVolatileQualifiedType(CXType T);
|
||||
|
||||
/**
|
||||
* \determine Determine whether a CXType has the "restrict" qualifier set,
|
||||
* without looking through typedefs that may have added "restrict" at a different level.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_isRestrictQualifiedType(CXType T);
|
||||
|
||||
/**
|
||||
* \brief For pointer types, returns the type of the pointee.
|
||||
*
|
||||
@ -1449,6 +1810,10 @@ CINDEX_LINKAGE CXType clang_getPointeeType(CXType T);
|
||||
*/
|
||||
CINDEX_LINKAGE CXCursor clang_getTypeDeclaration(CXType T);
|
||||
|
||||
/**
|
||||
* Returns the Objective-C type encoding for the specified declaration.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_getDeclObjCTypeEncoding(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the spelling of a given CXTypeKind.
|
||||
@ -1495,6 +1860,34 @@ enum CX_CXXAccessSpecifier {
|
||||
*/
|
||||
CINDEX_LINKAGE enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor);
|
||||
|
||||
/**
|
||||
* \brief Determine the number of overloaded declarations referenced by a
|
||||
* \c CXCursor_OverloadedDeclRef cursor.
|
||||
*
|
||||
* \param cursor The cursor whose overloaded declarations are being queried.
|
||||
*
|
||||
* \returns The number of overloaded declarations referenced by \c cursor. If it
|
||||
* is not a \c CXCursor_OverloadedDeclRef cursor, returns 0.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_getNumOverloadedDecls(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Retrieve a cursor for one of the overloaded declarations referenced
|
||||
* by a \c CXCursor_OverloadedDeclRef cursor.
|
||||
*
|
||||
* \param cursor The cursor whose overloaded declarations are being queried.
|
||||
*
|
||||
* \param index The zero-based index into the set of overloaded declarations in
|
||||
* the cursor.
|
||||
*
|
||||
* \returns A cursor representing the declaration referenced by the given
|
||||
* \c cursor at the specified \c index. If the cursor does not have an
|
||||
* associated set of overloaded declarations, or if the index is out of bounds,
|
||||
* returns \c clang_getNullCursor();
|
||||
*/
|
||||
CINDEX_LINKAGE CXCursor clang_getOverloadedDecl(CXCursor cursor,
|
||||
unsigned index);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -1591,6 +1984,29 @@ typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor,
|
||||
CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent,
|
||||
CXCursorVisitor visitor,
|
||||
CXClientData client_data);
|
||||
#ifdef __has_feature
|
||||
# if __has_feature(blocks)
|
||||
/**
|
||||
* \brief Visitor invoked for each cursor found by a traversal.
|
||||
*
|
||||
* This visitor block will be invoked for each cursor found by
|
||||
* clang_visitChildrenWithBlock(). Its first argument is the cursor being
|
||||
* visited, its second argument is the parent visitor for that cursor.
|
||||
*
|
||||
* The visitor should return one of the \c CXChildVisitResult values
|
||||
* to direct clang_visitChildrenWithBlock().
|
||||
*/
|
||||
typedef enum CXChildVisitResult
|
||||
(^CXCursorVisitorBlock)(CXCursor cursor, CXCursor parent);
|
||||
|
||||
/**
|
||||
* Visits the children of a cursor using the specified block. Behaves
|
||||
* identically to clang_visitChildren() in all other respects.
|
||||
*/
|
||||
unsigned clang_visitChildrenWithBlock(CXCursor parent,
|
||||
CXCursorVisitorBlock block);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
@ -1664,6 +2080,15 @@ CINDEX_LINKAGE CXString clang_constructUSR_ObjCProperty(const char *property,
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the display name for the entity referenced by this cursor.
|
||||
*
|
||||
* The display name contains extra information that helps identify the cursor,
|
||||
* such as the parameters of a function or template or the arguments of a
|
||||
* class template specialization.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_getCursorDisplayName(CXCursor);
|
||||
|
||||
/** \brief For a cursor that is a reference, retrieve a cursor representing the
|
||||
* entity that it references.
|
||||
*
|
||||
@ -1712,6 +2137,32 @@ CINDEX_LINKAGE CXCursor clang_getCursorDefinition(CXCursor);
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the canonical cursor corresponding to the given cursor.
|
||||
*
|
||||
* In the C family of languages, many kinds of entities can be declared several
|
||||
* times within a single translation unit. For example, a structure type can
|
||||
* be forward-declared (possibly multiple times) and later defined:
|
||||
*
|
||||
* \code
|
||||
* struct X;
|
||||
* struct X;
|
||||
* struct X {
|
||||
* int member;
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
* The declarations and the definition of \c X are represented by three
|
||||
* different cursors, all of which are declarations of the same underlying
|
||||
* entity. One of these cursor is considered the "canonical" cursor, which
|
||||
* is effectively the representative for the underlying entity. One can
|
||||
* determine if two cursors are declarations of the same underlying entity by
|
||||
* comparing their canonical cursors.
|
||||
*
|
||||
* \returns The canonical cursor for the entity referred to by the given cursor.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -1939,6 +2390,9 @@ CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor,
|
||||
unsigned *endLine,
|
||||
unsigned *endColumn);
|
||||
CINDEX_LINKAGE void clang_enableStackTraces(void);
|
||||
CINDEX_LINKAGE void clang_executeOnThread(void (*fn)(void*), void *user_data,
|
||||
unsigned stack_size);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -2243,7 +2697,7 @@ clang_getCompletionAvailability(CXCompletionString completion_string);
|
||||
* \brief Contains the results of code-completion.
|
||||
*
|
||||
* This data structure contains the results of code completion, as
|
||||
* produced by \c clang_codeComplete. Its contents must be freed by
|
||||
* produced by \c clang_codeCompleteAt(). Its contents must be freed by
|
||||
* \c clang_disposeCodeCompleteResults.
|
||||
*/
|
||||
typedef struct {
|
||||
@ -2259,99 +2713,6 @@ typedef struct {
|
||||
unsigned NumResults;
|
||||
} CXCodeCompleteResults;
|
||||
|
||||
/**
|
||||
* \brief Perform code completion at a given location in a source file.
|
||||
*
|
||||
* This function performs code completion at a particular file, line, and
|
||||
* column within source code, providing results that suggest potential
|
||||
* code snippets based on the context of the completion. The basic model
|
||||
* for code completion is that Clang will parse a complete source file,
|
||||
* performing syntax checking up to the location where code-completion has
|
||||
* been requested. At that point, a special code-completion token is passed
|
||||
* to the parser, which recognizes this token and determines, based on the
|
||||
* current location in the C/Objective-C/C++ grammar and the state of
|
||||
* semantic analysis, what completions to provide. These completions are
|
||||
* returned via a new \c CXCodeCompleteResults structure.
|
||||
*
|
||||
* Code completion itself is meant to be triggered by the client when the
|
||||
* user types punctuation characters or whitespace, at which point the
|
||||
* code-completion location will coincide with the cursor. For example, if \c p
|
||||
* is a pointer, code-completion might be triggered after the "-" and then
|
||||
* after the ">" in \c p->. When the code-completion location is afer the ">",
|
||||
* the completion results will provide, e.g., the members of the struct that
|
||||
* "p" points to. The client is responsible for placing the cursor at the
|
||||
* beginning of the token currently being typed, then filtering the results
|
||||
* based on the contents of the token. For example, when code-completing for
|
||||
* the expression \c p->get, the client should provide the location just after
|
||||
* the ">" (e.g., pointing at the "g") to this code-completion hook. Then, the
|
||||
* client can filter the results based on the current token text ("get"), only
|
||||
* showing those results that start with "get". The intent of this interface
|
||||
* is to separate the relatively high-latency acquisition of code-completion
|
||||
* results from the filtering of results on a per-character basis, which must
|
||||
* have a lower latency.
|
||||
*
|
||||
* \param CIdx the \c CXIndex instance that will be used to perform code
|
||||
* completion.
|
||||
*
|
||||
* \param source_filename the name of the source file that should be parsed to
|
||||
* perform code-completion. This source file must be the same as or include the
|
||||
* filename described by \p complete_filename, or no code-completion results
|
||||
* will be produced. NOTE: One can also specify NULL for this argument if the
|
||||
* source file is included in command_line_args.
|
||||
*
|
||||
* \param num_command_line_args the number of command-line arguments stored in
|
||||
* \p command_line_args.
|
||||
*
|
||||
* \param command_line_args the command-line arguments to pass to the Clang
|
||||
* compiler to build the given source file. This should include all of the
|
||||
* necessary include paths, language-dialect switches, precompiled header
|
||||
* includes, etc., but should not include any information specific to
|
||||
* code completion.
|
||||
*
|
||||
* \param num_unsaved_files the number of unsaved file entries in \p
|
||||
* unsaved_files.
|
||||
*
|
||||
* \param unsaved_files the files that have not yet been saved to disk
|
||||
* but may be required for code completion, including the contents of
|
||||
* those files. The contents and name of these files (as specified by
|
||||
* CXUnsavedFile) are copied when necessary, so the client only needs to
|
||||
* guarantee their validity until the call to this function returns.
|
||||
*
|
||||
* \param complete_filename the name of the source file where code completion
|
||||
* should be performed. In many cases, this name will be the same as the
|
||||
* source filename. However, the completion filename may also be a file
|
||||
* included by the source file, which is required when producing
|
||||
* code-completion results for a header.
|
||||
*
|
||||
* \param complete_line the line at which code-completion should occur.
|
||||
*
|
||||
* \param complete_column the column at which code-completion should occur.
|
||||
* Note that the column should point just after the syntactic construct that
|
||||
* initiated code completion, and not in the middle of a lexical token.
|
||||
*
|
||||
* \param diag_callback callback function that will receive any diagnostics
|
||||
* emitted while processing this source file. If NULL, diagnostics will be
|
||||
* suppressed.
|
||||
*
|
||||
* \param diag_client_data client data that will be passed to the diagnostic
|
||||
* callback function.
|
||||
*
|
||||
* \returns if successful, a new CXCodeCompleteResults structure
|
||||
* containing code-completion results, which should eventually be
|
||||
* freed with \c clang_disposeCodeCompleteResults(). If code
|
||||
* completion fails, returns NULL.
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
|
||||
const char *source_filename,
|
||||
int num_command_line_args,
|
||||
const char * const *command_line_args,
|
||||
unsigned num_unsaved_files,
|
||||
struct CXUnsavedFile *unsaved_files,
|
||||
const char *complete_filename,
|
||||
unsigned complete_line,
|
||||
unsigned complete_column);
|
||||
|
||||
/**
|
||||
* \brief Flags that can be passed to \c clang_codeCompleteAt() to
|
||||
* modify its behavior.
|
||||
@ -2510,12 +2871,6 @@ CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results,
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_getClangVersion();
|
||||
|
||||
/**
|
||||
* \brief Return a version string, suitable for showing to a user, but not
|
||||
* intended to be parsed (the format is not guaranteed to be stable).
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* \brief Visitor invoked for each file in a translation unit
|
||||
* (used with clang_getInclusions()).
|
||||
|
@ -19,6 +19,7 @@ namespace clang {
|
||||
class CXXRecordDecl;
|
||||
class DeclGroupRef;
|
||||
class HandleTagDeclDefinition;
|
||||
class ASTMutationListener;
|
||||
class ASTDeserializationListener; // layering violation because void* is ugly
|
||||
class SemaConsumer; // layering violation required for safe SemaConsumer
|
||||
class TagDecl;
|
||||
@ -86,10 +87,13 @@ class ASTConsumer {
|
||||
/// it was actually used.
|
||||
virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
|
||||
|
||||
/// \brief If the consumer is interested in entities getting modified after
|
||||
/// their initial creation, it should return a pointer to
|
||||
/// a GetASTMutationListener here.
|
||||
virtual ASTMutationListener *GetASTMutationListener() { return 0; }
|
||||
|
||||
/// \brief If the consumer is interested in entities being deserialized from
|
||||
/// AST files, it should return a pointer to a ASTDeserializationListener here
|
||||
///
|
||||
/// The return type is void* because ASTDS lives in Frontend.
|
||||
virtual ASTDeserializationListener *GetASTDeserializationListener() { return 0; }
|
||||
|
||||
/// PrintStats - If desired, print any statistics.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,7 @@
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM,
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
|
||||
#define ASTSTART
|
||||
#include "clang/Basic/DiagnosticASTKinds.inc"
|
||||
#undef DIAG
|
||||
|
@ -45,13 +45,13 @@ namespace clang {
|
||||
|
||||
/// \brief The file managers we're importing to and from.
|
||||
FileManager &ToFileManager, &FromFileManager;
|
||||
|
||||
/// \brief The diagnostics object that we should use to emit diagnostics.
|
||||
Diagnostic &Diags;
|
||||
|
||||
/// \brief Whether to perform a minimal import.
|
||||
bool Minimal;
|
||||
|
||||
/// \brief Mapping from the already-imported types in the "from" context
|
||||
/// to the corresponding types in the "to" context.
|
||||
llvm::DenseMap<Type *, Type *> ImportedTypes;
|
||||
llvm::DenseMap<const Type *, const Type *> ImportedTypes;
|
||||
|
||||
/// \brief Mapping from the already-imported declarations in the "from"
|
||||
/// context to the corresponding declarations in the "to" context.
|
||||
@ -63,7 +63,7 @@ namespace clang {
|
||||
|
||||
/// \brief Mapping from the already-imported FileIDs in the "from" source
|
||||
/// manager to the corresponding FileIDs in the "to" source manager.
|
||||
llvm::DenseMap<unsigned, FileID> ImportedFileIDs;
|
||||
llvm::DenseMap<FileID, FileID> ImportedFileIDs;
|
||||
|
||||
/// \brief Imported, anonymous tag declarations that are missing their
|
||||
/// corresponding typedefs.
|
||||
@ -74,12 +74,29 @@ namespace clang {
|
||||
NonEquivalentDeclSet NonEquivalentDecls;
|
||||
|
||||
public:
|
||||
ASTImporter(Diagnostic &Diags,
|
||||
ASTContext &ToContext, FileManager &ToFileManager,
|
||||
ASTContext &FromContext, FileManager &FromFileManager);
|
||||
/// \brief Create a new AST importer.
|
||||
///
|
||||
/// \param ToContext The context we'll be importing into.
|
||||
///
|
||||
/// \param ToFileManager The file manager we'll be importing into.
|
||||
///
|
||||
/// \param FromContext The context we'll be importing from.
|
||||
///
|
||||
/// \param FromFileManager The file manager we'll be importing into.
|
||||
///
|
||||
/// \param MinimalImport If true, the importer will attempt to import
|
||||
/// as little as it can, e.g., by importing declarations as forward
|
||||
/// declarations that can be completed at a later point.
|
||||
ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
|
||||
ASTContext &FromContext, FileManager &FromFileManager,
|
||||
bool MinimalImport);
|
||||
|
||||
virtual ~ASTImporter();
|
||||
|
||||
/// \brief Whether the importer will perform a minimal import, creating
|
||||
/// to-be-completed forward declarations when possible.
|
||||
bool isMinimalImport() const { return Minimal; }
|
||||
|
||||
/// \brief Import the given type from the "from" context into the "to"
|
||||
/// context.
|
||||
///
|
||||
@ -129,6 +146,10 @@ namespace clang {
|
||||
/// context, or NULL if an error occurred.
|
||||
NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS);
|
||||
|
||||
/// \brief Import the goven template name from the "from" context into the
|
||||
/// "to" context.
|
||||
TemplateName Import(TemplateName From);
|
||||
|
||||
/// \brief Import the given source location from the "from" context into
|
||||
/// the "to" context.
|
||||
///
|
||||
@ -154,7 +175,7 @@ namespace clang {
|
||||
/// into the "to" context.
|
||||
///
|
||||
/// \returns the equivalent identifier in the "to" context.
|
||||
IdentifierInfo *Import(IdentifierInfo *FromId);
|
||||
IdentifierInfo *Import(const IdentifierInfo *FromId);
|
||||
|
||||
/// \brief Import the given Objective-C selector from the "from"
|
||||
/// context into the "to" context.
|
||||
@ -169,6 +190,12 @@ namespace clang {
|
||||
/// context.
|
||||
FileID Import(FileID);
|
||||
|
||||
/// \brief Import the definition of the given declaration, including all of
|
||||
/// the declarations it contains.
|
||||
///
|
||||
/// This routine is intended to be used
|
||||
void ImportDefinition(Decl *From);
|
||||
|
||||
/// \brief Cope with a name conflict when importing a declaration into the
|
||||
/// given context.
|
||||
///
|
||||
@ -212,9 +239,6 @@ namespace clang {
|
||||
|
||||
/// \brief Retrieve the file manager that AST nodes are being imported from.
|
||||
FileManager &getFromFileManager() const { return FromFileManager; }
|
||||
|
||||
/// \brief Retrieve the diagnostic formatter.
|
||||
Diagnostic &getDiags() const { return Diags; }
|
||||
|
||||
/// \brief Report a diagnostic in the "to" context.
|
||||
DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID);
|
||||
@ -228,12 +252,13 @@ namespace clang {
|
||||
/// \brief Note that we have imported the "from" declaration by mapping it
|
||||
/// to the (potentially-newly-created) "to" declaration.
|
||||
///
|
||||
/// \returns \p To
|
||||
Decl *Imported(Decl *From, Decl *To);
|
||||
/// Subclasses can override this function to observe all of the \c From ->
|
||||
/// \c To declaration mappings as they are imported.
|
||||
virtual Decl *Imported(Decl *From, Decl *To);
|
||||
|
||||
/// \brief Determine whether the given types are structurally
|
||||
/// equivalent.
|
||||
bool IsStructurallyEquivalent(QualType From, QualType To);
|
||||
bool IsStructurallyEquivalent(QualType From, QualType To);
|
||||
};
|
||||
}
|
||||
|
||||
|
48
include/clang/AST/ASTMutationListener.h
Normal file
48
include/clang/AST/ASTMutationListener.h
Normal file
@ -0,0 +1,48 @@
|
||||
//===--- ASTMutationListener.h - AST Mutation Interface --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ASTMutationListener interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
|
||||
#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class TagDecl;
|
||||
class CXXRecordDecl;
|
||||
class ClassTemplateDecl;
|
||||
class ClassTemplateSpecializationDecl;
|
||||
|
||||
/// \brief An abstract interface that should be implemented by listeners
|
||||
/// that want to be notified when an AST entity gets modified after its
|
||||
/// initial creation.
|
||||
class ASTMutationListener {
|
||||
public:
|
||||
virtual ~ASTMutationListener();
|
||||
|
||||
/// \brief A new TagDecl definition was completed.
|
||||
virtual void CompletedTagDefinition(const TagDecl *D) { }
|
||||
|
||||
/// \brief A new declaration with name has been added to a DeclContext.
|
||||
virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D) {}
|
||||
|
||||
/// \brief An implicit member was added after the definition was completed.
|
||||
virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {}
|
||||
|
||||
/// \brief A template specialization (or partial one) was added to the
|
||||
/// template declaration.
|
||||
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
|
||||
const ClassTemplateSpecializationDecl *D) {}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -36,19 +36,19 @@ namespace clang {
|
||||
}
|
||||
|
||||
// Defined in ASTContext.h
|
||||
void *operator new(size_t Bytes, clang::ASTContext &C,
|
||||
void *operator new(size_t Bytes, const clang::ASTContext &C,
|
||||
size_t Alignment = 16) throw ();
|
||||
// FIXME: Being forced to not have a default argument here due to redeclaration
|
||||
// rules on default arguments sucks
|
||||
void *operator new[](size_t Bytes, clang::ASTContext &C,
|
||||
void *operator new[](size_t Bytes, const clang::ASTContext &C,
|
||||
size_t Alignment) throw ();
|
||||
|
||||
// It is good practice to pair new/delete operators. Also, MSVC gives many
|
||||
// warnings if a matching delete overload is not declared, even though the
|
||||
// throw() spec guarantees it will not be implicitly called.
|
||||
void operator delete(void *Ptr, clang::ASTContext &C, size_t)
|
||||
void operator delete(void *Ptr, const clang::ASTContext &C, size_t)
|
||||
throw ();
|
||||
void operator delete[](void *Ptr, clang::ASTContext &C, size_t)
|
||||
void operator delete[](void *Ptr, const clang::ASTContext &C, size_t)
|
||||
throw ();
|
||||
|
||||
namespace clang {
|
||||
@ -58,9 +58,10 @@ class Attr {
|
||||
private:
|
||||
SourceLocation Loc;
|
||||
unsigned AttrKind : 16;
|
||||
bool Inherited : 1;
|
||||
|
||||
protected:
|
||||
bool Inherited : 1;
|
||||
|
||||
virtual ~Attr();
|
||||
|
||||
void* operator new(size_t bytes) throw() {
|
||||
@ -88,10 +89,6 @@ class Attr {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Whether this attribute should be merged to new
|
||||
/// declarations.
|
||||
virtual bool isMerged() const { return true; }
|
||||
|
||||
attr::Kind getKind() const {
|
||||
return static_cast<attr::Kind>(AttrKind);
|
||||
}
|
||||
@ -100,7 +97,6 @@ class Attr {
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
bool isInherited() const { return Inherited; }
|
||||
void setInherited(bool I) { Inherited = I; }
|
||||
|
||||
// Clone this attribute.
|
||||
virtual Attr* clone(ASTContext &C) const = 0;
|
||||
@ -109,6 +105,21 @@ class Attr {
|
||||
static bool classof(const Attr *) { return true; }
|
||||
};
|
||||
|
||||
class InheritableAttr : public Attr {
|
||||
protected:
|
||||
InheritableAttr(attr::Kind AK, SourceLocation L)
|
||||
: Attr(AK, L) {}
|
||||
|
||||
public:
|
||||
void setInherited(bool I) { Inherited = I; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() <= attr::LAST_INHERITABLE;
|
||||
}
|
||||
static bool classof(const InheritableAttr *) { return true; }
|
||||
};
|
||||
|
||||
#include "clang/AST/Attrs.inc"
|
||||
|
||||
/// AttrVec - A vector of Attr, which is how they are stored on the AST.
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
@ -359,7 +360,11 @@ class OverridingMethods {
|
||||
/// subobjects of that type.
|
||||
class CXXFinalOverriderMap
|
||||
: public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { };
|
||||
|
||||
|
||||
/// \brief A set of all the primary bases for a class.
|
||||
class CXXIndirectPrimaryBaseSet
|
||||
: public llvm::SmallSet<const CXXRecordDecl*, 32> { };
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -66,7 +66,16 @@ class CanQual {
|
||||
|
||||
/// \brief Retrieve the underlying type pointer, which refers to a
|
||||
/// canonical type.
|
||||
T *getTypePtr() const { return cast_or_null<T>(Stored.getTypePtr()); }
|
||||
///
|
||||
/// The underlying pointer must not be NULL.
|
||||
const T *getTypePtr() const { return cast<T>(Stored.getTypePtr()); }
|
||||
|
||||
/// \brief Retrieve the underlying type pointer, which refers to a
|
||||
/// canonical type, or NULL.
|
||||
///
|
||||
const T *getTypePtrOrNull() const {
|
||||
return cast_or_null<T>(Stored.getTypePtrOrNull());
|
||||
}
|
||||
|
||||
/// \brief Implicit conversion to a qualified type.
|
||||
operator QualType() const { return Stored; }
|
||||
@ -78,6 +87,8 @@ class CanQual {
|
||||
return Stored.isNull();
|
||||
}
|
||||
|
||||
SplitQualType split() const { return Stored.split(); }
|
||||
|
||||
/// \brief Retrieve a canonical type pointer with a different static type,
|
||||
/// upcasting or downcasting as needed.
|
||||
///
|
||||
@ -216,7 +227,7 @@ class CanProxyBase {
|
||||
|
||||
public:
|
||||
/// \brief Retrieve the pointer to the underlying Type
|
||||
T* getTypePtr() const { return Stored.getTypePtr(); }
|
||||
const T *getTypePtr() const { return Stored.getTypePtr(); }
|
||||
|
||||
/// \brief Implicit conversion to the underlying pointer.
|
||||
///
|
||||
@ -225,7 +236,7 @@ class CanProxyBase {
|
||||
/// @code
|
||||
/// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... }
|
||||
/// @endcode
|
||||
operator const T*() const { return this->Stored.getTypePtr(); }
|
||||
operator const T*() const { return this->Stored.getTypePtrOrNull(); }
|
||||
|
||||
/// \brief Try to convert the given canonical type to a specific structural
|
||||
/// type.
|
||||
@ -336,7 +347,7 @@ namespace llvm {
|
||||
/// to return smart pointer (proxies?).
|
||||
template<typename T>
|
||||
struct simplify_type<const ::clang::CanQual<T> > {
|
||||
typedef T* SimpleType;
|
||||
typedef const T *SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) {
|
||||
return Val.getTypePtr();
|
||||
}
|
||||
@ -630,7 +641,6 @@ struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getAddressSpace)
|
||||
};
|
||||
|
||||
template<>
|
||||
|
@ -14,7 +14,9 @@
|
||||
#ifndef LLVM_CLANG_AST_CHARUNITS_H
|
||||
#define LLVM_CLANG_AST_CHARUNITS_H
|
||||
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -131,12 +133,24 @@ namespace clang {
|
||||
CharUnits operator- (const CharUnits &Other) const {
|
||||
return CharUnits(Quantity - Other.Quantity);
|
||||
}
|
||||
CharUnits operator- () const {
|
||||
return CharUnits(-Quantity);
|
||||
}
|
||||
|
||||
|
||||
// Conversions.
|
||||
|
||||
/// getQuantity - Get the raw integer representation of this quantity.
|
||||
QuantityType getQuantity() const { return Quantity; }
|
||||
|
||||
/// RoundUpToAlignment - Returns the next integer (mod 2**64) that is
|
||||
/// greater than or equal to this quantity and is a multiple of \arg
|
||||
/// Align. Align must be non-zero.
|
||||
CharUnits RoundUpToAlignment(const CharUnits &Align) {
|
||||
return CharUnits(llvm::RoundUpToAlignment(Quantity,
|
||||
Align.Quantity));
|
||||
}
|
||||
|
||||
|
||||
}; // class CharUnit
|
||||
} // namespace clang
|
||||
@ -146,4 +160,38 @@ inline clang::CharUnits operator* (clang::CharUnits::QuantityType Scale,
|
||||
return CU * Scale;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<> struct DenseMapInfo<clang::CharUnits> {
|
||||
static clang::CharUnits getEmptyKey() {
|
||||
clang::CharUnits::QuantityType Quantity =
|
||||
DenseMapInfo<clang::CharUnits::QuantityType>::getEmptyKey();
|
||||
|
||||
return clang::CharUnits::fromQuantity(Quantity);
|
||||
}
|
||||
|
||||
static clang::CharUnits getTombstoneKey() {
|
||||
clang::CharUnits::QuantityType Quantity =
|
||||
DenseMapInfo<clang::CharUnits::QuantityType>::getTombstoneKey();
|
||||
|
||||
return clang::CharUnits::fromQuantity(Quantity);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::CharUnits &CU) {
|
||||
clang::CharUnits::QuantityType Quantity = CU.getQuantity();
|
||||
return DenseMapInfo<clang::CharUnits::QuantityType>::getHashValue(Quantity);
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::CharUnits &LHS,
|
||||
const clang::CharUnits &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct isPodLike<clang::CharUnits> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CLANG_AST_CHARUNITS_H
|
||||
|
@ -36,6 +36,7 @@ class FunctionTemplateSpecializationInfo;
|
||||
class DependentFunctionTemplateSpecializationInfo;
|
||||
class TypeLoc;
|
||||
class UnresolvedSetImpl;
|
||||
class LabelStmt;
|
||||
|
||||
/// \brief A container of type source information.
|
||||
///
|
||||
@ -196,9 +197,86 @@ class NamedDecl : public Decl {
|
||||
/// determine whether it's an instance member of its class.
|
||||
bool isCXXInstanceMember() const;
|
||||
|
||||
class LinkageInfo {
|
||||
Linkage linkage_;
|
||||
Visibility visibility_;
|
||||
bool explicit_;
|
||||
|
||||
public:
|
||||
LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility),
|
||||
explicit_(false) {}
|
||||
LinkageInfo(Linkage L, Visibility V, bool E)
|
||||
: linkage_(L), visibility_(V), explicit_(E) {}
|
||||
|
||||
static LinkageInfo external() {
|
||||
return LinkageInfo();
|
||||
}
|
||||
static LinkageInfo internal() {
|
||||
return LinkageInfo(InternalLinkage, DefaultVisibility, false);
|
||||
}
|
||||
static LinkageInfo uniqueExternal() {
|
||||
return LinkageInfo(UniqueExternalLinkage, DefaultVisibility, false);
|
||||
}
|
||||
static LinkageInfo none() {
|
||||
return LinkageInfo(NoLinkage, DefaultVisibility, false);
|
||||
}
|
||||
|
||||
Linkage linkage() const { return linkage_; }
|
||||
Visibility visibility() const { return visibility_; }
|
||||
bool visibilityExplicit() const { return explicit_; }
|
||||
|
||||
void setLinkage(Linkage L) { linkage_ = L; }
|
||||
void setVisibility(Visibility V) { visibility_ = V; }
|
||||
void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
|
||||
void setVisibility(LinkageInfo Other) {
|
||||
setVisibility(Other.visibility(), Other.visibilityExplicit());
|
||||
}
|
||||
|
||||
void mergeLinkage(Linkage L) {
|
||||
setLinkage(minLinkage(linkage(), L));
|
||||
}
|
||||
void mergeLinkage(LinkageInfo Other) {
|
||||
setLinkage(minLinkage(linkage(), Other.linkage()));
|
||||
}
|
||||
|
||||
void mergeVisibility(Visibility V) {
|
||||
setVisibility(minVisibility(visibility(), V));
|
||||
}
|
||||
void mergeVisibility(Visibility V, bool E) {
|
||||
setVisibility(minVisibility(visibility(), V), visibilityExplicit() || E);
|
||||
}
|
||||
void mergeVisibility(LinkageInfo Other) {
|
||||
mergeVisibility(Other.visibility(), Other.visibilityExplicit());
|
||||
}
|
||||
|
||||
void merge(LinkageInfo Other) {
|
||||
mergeLinkage(Other);
|
||||
mergeVisibility(Other);
|
||||
}
|
||||
void merge(std::pair<Linkage,Visibility> LV) {
|
||||
mergeLinkage(LV.first);
|
||||
mergeVisibility(LV.second);
|
||||
}
|
||||
|
||||
friend LinkageInfo merge(LinkageInfo L, LinkageInfo R) {
|
||||
L.merge(R);
|
||||
return L;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Determine what kind of linkage this entity has.
|
||||
Linkage getLinkage() const;
|
||||
|
||||
/// \brief Determines the visibility of this entity.
|
||||
Visibility getVisibility() const { return getLinkageAndVisibility().visibility(); }
|
||||
|
||||
/// \brief Determines the linkage and visibility of this entity.
|
||||
LinkageInfo getLinkageAndVisibility() const;
|
||||
|
||||
/// \brief Clear the linkage cache in response to a change
|
||||
/// to the declaration.
|
||||
void ClearLinkageCache();
|
||||
|
||||
/// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for
|
||||
/// the underlying named decl.
|
||||
NamedDecl *getUnderlyingDecl();
|
||||
@ -217,6 +295,29 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// LabelDecl - Represents the declaration of a label. Labels also have a
|
||||
/// corresponding LabelStmt, which indicates the position that the label was
|
||||
/// defined at. For normal labels, the location of the decl is the same as the
|
||||
/// location of the statement. For GNU local labels (__label__), the decl
|
||||
/// location is where the __label__ is.
|
||||
class LabelDecl : public NamedDecl {
|
||||
LabelStmt *TheStmt;
|
||||
LabelDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *II, LabelStmt *S)
|
||||
: NamedDecl(Label, DC, L, II), TheStmt(S) {}
|
||||
|
||||
public:
|
||||
static LabelDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *II);
|
||||
|
||||
LabelStmt *getStmt() const { return TheStmt; }
|
||||
void setStmt(LabelStmt *T) { TheStmt = T; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const LabelDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Label; }
|
||||
};
|
||||
|
||||
/// NamespaceDecl - Represent a C++ namespace.
|
||||
class NamespaceDecl : public NamedDecl, public DeclContext {
|
||||
bool IsInline : 1;
|
||||
@ -232,7 +333,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
|
||||
// NextNamespace points to the next extended declaration.
|
||||
// OrigNamespace points to the original namespace declaration.
|
||||
// OrigNamespace of the first namespace decl points to its anonymous namespace
|
||||
NamespaceDecl *NextNamespace;
|
||||
LazyDeclPtr NextNamespace;
|
||||
|
||||
/// \brief A pointer to either the original namespace definition for
|
||||
/// this namespace (if the boolean value is false) or the anonymous
|
||||
@ -250,7 +351,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
|
||||
: NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace),
|
||||
IsInline(false), NextNamespace(0), OrigOrAnonNamespace(0, true) { }
|
||||
IsInline(false), NextNamespace(), OrigOrAnonNamespace(0, true) { }
|
||||
|
||||
public:
|
||||
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
@ -281,8 +382,10 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
/// \brief Return the next extended namespace declaration or null if there
|
||||
/// is none.
|
||||
NamespaceDecl *getNextNamespace() { return NextNamespace; }
|
||||
const NamespaceDecl *getNextNamespace() const { return NextNamespace; }
|
||||
NamespaceDecl *getNextNamespace();
|
||||
const NamespaceDecl *getNextNamespace() const {
|
||||
return const_cast<NamespaceDecl *>(this)->getNextNamespace();
|
||||
}
|
||||
|
||||
/// \brief Set the next extended namespace declaration.
|
||||
void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
|
||||
@ -331,9 +434,9 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
SourceLocation getLBracLoc() const { return LBracLoc; }
|
||||
SourceLocation getRBracLoc() const { return RBracLoc; }
|
||||
void setLBracLoc(SourceLocation LBrace) { LBracLoc = LBrace; }
|
||||
void setRBracLoc(SourceLocation RBrace) { RBracLoc = RBrace; }
|
||||
|
||||
void setLBracLoc(SourceLocation L) { LBracLoc = L; }
|
||||
void setRBracLoc(SourceLocation R) { RBracLoc = R; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const NamespaceDecl *D) { return true; }
|
||||
@ -471,6 +574,9 @@ class DeclaratorDecl : public ValueDecl {
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstDeclarator && K <= lastDeclarator;
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// \brief Structure used to store a statement, the constant value to
|
||||
@ -545,15 +651,21 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// \brief Whether this local variable could be allocated in the return
|
||||
/// slot of its function, enabling the named return value optimization (NRVO).
|
||||
bool NRVOVariable : 1;
|
||||
|
||||
/// \brief Whether this variable has a deduced C++0x auto type for which we're
|
||||
/// currently parsing the initializer.
|
||||
bool ParsingAutoInit : 1;
|
||||
|
||||
friend class StmtIteratorBase;
|
||||
friend class ASTDeclReader;
|
||||
|
||||
protected:
|
||||
VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, TypeSourceInfo *TInfo, StorageClass SC,
|
||||
StorageClass SCAsWritten)
|
||||
: DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(),
|
||||
ThreadSpecified(false), HasCXXDirectInit(false),
|
||||
ExceptionVar(false), NRVOVariable(false) {
|
||||
ExceptionVar(false), NRVOVariable(false), ParsingAutoInit(false) {
|
||||
SClass = SC;
|
||||
SClassAsWritten = SCAsWritten;
|
||||
}
|
||||
@ -582,10 +694,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
StorageClass getStorageClassAsWritten() const {
|
||||
return (StorageClass) SClassAsWritten;
|
||||
}
|
||||
void setStorageClass(StorageClass SC) {
|
||||
assert(isLegalForVariable(SC));
|
||||
SClass = SC;
|
||||
}
|
||||
void setStorageClass(StorageClass SC);
|
||||
void setStorageClassAsWritten(StorageClass SC) {
|
||||
assert(isLegalForVariable(SC));
|
||||
SClassAsWritten = SC;
|
||||
@ -630,13 +739,13 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// external, C linkage.
|
||||
bool isExternC() const;
|
||||
|
||||
/// isBlockVarDecl - Returns true for local variable declarations. Note that
|
||||
/// this includes static variables inside of functions. It also includes
|
||||
/// variables inside blocks.
|
||||
/// isLocalVarDecl - Returns true for local variable declarations
|
||||
/// other than parameters. Note that this includes static variables
|
||||
/// inside of functions. It also includes variables inside blocks.
|
||||
///
|
||||
/// void foo() { int x; static int y; extern int z; }
|
||||
///
|
||||
bool isBlockVarDecl() const {
|
||||
bool isLocalVarDecl() const {
|
||||
if (getKind() != Decl::Var)
|
||||
return false;
|
||||
if (const DeclContext *DC = getDeclContext())
|
||||
@ -644,8 +753,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// isFunctionOrMethodVarDecl - Similar to isBlockVarDecl, but excludes
|
||||
/// variables declared in blocks.
|
||||
/// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but
|
||||
/// excludes variables declared in blocks.
|
||||
bool isFunctionOrMethodVarDecl() const {
|
||||
if (getKind() != Decl::Var)
|
||||
return false;
|
||||
@ -683,6 +792,10 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// definition.
|
||||
DefinitionKind isThisDeclarationADefinition() const;
|
||||
|
||||
/// \brief Check whether this variable is defined in this
|
||||
/// translation unit.
|
||||
DefinitionKind hasDefinition() const;
|
||||
|
||||
/// \brief Get the tentative definition that acts as the real definition in
|
||||
/// a TU. Returns null if there is a proper definition available.
|
||||
VarDecl *getActingDefinition();
|
||||
@ -733,7 +846,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
const Expr *getAnyInitializer(const VarDecl *&D) const;
|
||||
|
||||
bool hasInit() const {
|
||||
return !Init.isNull();
|
||||
return !Init.isNull() && (Init.is<Stmt *>() || Init.is<EvaluatedStmt *>());
|
||||
}
|
||||
const Expr *getInit() const {
|
||||
if (Init.isNull())
|
||||
@ -776,6 +889,18 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
|
||||
void setInit(Expr *I);
|
||||
|
||||
/// \brief Check whether we are in the process of parsing an initializer
|
||||
/// needed to deduce the type of this variable.
|
||||
bool isParsingAutoInit() const {
|
||||
return ParsingAutoInit;
|
||||
}
|
||||
|
||||
/// \brief Note whether we are currently parsing an initializer needed to
|
||||
/// deduce the type of this variable.
|
||||
void setParsingAutoInit(bool P) {
|
||||
ParsingAutoInit = P;
|
||||
}
|
||||
|
||||
EvaluatedStmt *EnsureEvaluatedStmt() const {
|
||||
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
|
||||
if (!Eval) {
|
||||
@ -928,7 +1053,9 @@ class ImplicitParamDecl : public VarDecl {
|
||||
protected:
|
||||
ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType Tw)
|
||||
: VarDecl(DK, DC, L, Id, Tw, /*TInfo=*/0, SC_None, SC_None) {}
|
||||
: VarDecl(DK, DC, L, Id, Tw, /*TInfo=*/0, SC_None, SC_None) {
|
||||
setImplicit();
|
||||
}
|
||||
public:
|
||||
static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
@ -1046,6 +1173,10 @@ class ParmVarDecl : public VarDecl {
|
||||
return getType();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this parameter is actually a function
|
||||
/// parameter pack.
|
||||
bool isParameterPack() const;
|
||||
|
||||
/// setOwningFunction - Sets the function declaration that owns this
|
||||
/// ParmVarDecl. Since ParmVarDecls are often created before the
|
||||
/// FunctionDecls that own them, this routine is required to update
|
||||
@ -1096,13 +1227,13 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
unsigned SClass : 2;
|
||||
unsigned SClassAsWritten : 2;
|
||||
bool IsInline : 1;
|
||||
bool IsInlineSpecified : 1;
|
||||
bool IsVirtualAsWritten : 1;
|
||||
bool IsPure : 1;
|
||||
bool HasInheritedPrototype : 1;
|
||||
bool HasWrittenPrototype : 1;
|
||||
bool IsDeleted : 1;
|
||||
bool IsTrivial : 1; // sunk from CXXMethodDecl
|
||||
bool IsCopyAssignment : 1; // sunk from CXXMethodDecl
|
||||
bool HasImplicitReturnZero : 1;
|
||||
|
||||
/// \brief End part of this FunctionDecl's source range.
|
||||
@ -1136,19 +1267,54 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// declaration name embedded in the DeclaratorDecl base class.
|
||||
DeclarationNameLoc DNLoc;
|
||||
|
||||
/// \brief Specify that this function declaration is actually a function
|
||||
/// template specialization.
|
||||
///
|
||||
/// \param C the ASTContext.
|
||||
///
|
||||
/// \param Template the function template that this function template
|
||||
/// specialization specializes.
|
||||
///
|
||||
/// \param TemplateArgs the template arguments that produced this
|
||||
/// function template specialization from the template.
|
||||
///
|
||||
/// \param InsertPos If non-NULL, the position in the function template
|
||||
/// specialization set where the function template specialization data will
|
||||
/// be inserted.
|
||||
///
|
||||
/// \param TSK the kind of template specialization this is.
|
||||
///
|
||||
/// \param TemplateArgsAsWritten location info of template arguments.
|
||||
///
|
||||
/// \param PointOfInstantiation point at which the function template
|
||||
/// specialization was first instantiated.
|
||||
void setFunctionTemplateSpecialization(ASTContext &C,
|
||||
FunctionTemplateDecl *Template,
|
||||
const TemplateArgumentList *TemplateArgs,
|
||||
void *InsertPos,
|
||||
TemplateSpecializationKind TSK,
|
||||
const TemplateArgumentListInfo *TemplateArgsAsWritten,
|
||||
SourceLocation PointOfInstantiation);
|
||||
|
||||
/// \brief Specify that this record is an instantiation of the
|
||||
/// member function FD.
|
||||
void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD,
|
||||
TemplateSpecializationKind TSK);
|
||||
|
||||
void setParams(ASTContext &C, ParmVarDecl **NewParamInfo, unsigned NumParams);
|
||||
|
||||
protected:
|
||||
FunctionDecl(Kind DK, DeclContext *DC, const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
StorageClass S, StorageClass SCAsWritten, bool isInline)
|
||||
StorageClass S, StorageClass SCAsWritten, bool isInlineSpecified)
|
||||
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo),
|
||||
DeclContext(DK),
|
||||
ParamInfo(0), Body(),
|
||||
SClass(S), SClassAsWritten(SCAsWritten), IsInline(isInline),
|
||||
SClass(S), SClassAsWritten(SCAsWritten),
|
||||
IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified),
|
||||
IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
|
||||
HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
|
||||
IsCopyAssignment(false),
|
||||
HasImplicitReturnZero(false),
|
||||
EndRangeLoc(NameInfo.getEndLoc()),
|
||||
HasImplicitReturnZero(false), EndRangeLoc(NameInfo.getEndLoc()),
|
||||
TemplateOrSpecialization(),
|
||||
DNLoc(NameInfo.getInfo()) {}
|
||||
|
||||
@ -1169,11 +1335,11 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
TypeSourceInfo *TInfo,
|
||||
StorageClass S = SC_None,
|
||||
StorageClass SCAsWritten = SC_None,
|
||||
bool isInline = false,
|
||||
bool isInlineSpecified = false,
|
||||
bool hasWrittenPrototype = true) {
|
||||
DeclarationNameInfo NameInfo(N, L);
|
||||
return FunctionDecl::Create(C, DC, NameInfo, T, TInfo, S, SCAsWritten,
|
||||
isInline, hasWrittenPrototype);
|
||||
isInlineSpecified, hasWrittenPrototype);
|
||||
}
|
||||
|
||||
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
@ -1181,7 +1347,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
StorageClass S = SC_None,
|
||||
StorageClass SCAsWritten = SC_None,
|
||||
bool isInline = false,
|
||||
bool isInlineSpecified = false,
|
||||
bool hasWrittenPrototype = true);
|
||||
|
||||
DeclarationNameInfo getNameInfo() const {
|
||||
@ -1246,7 +1412,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// Whether this virtual function is pure, i.e. makes the containing class
|
||||
/// abstract.
|
||||
bool isPure() const { return IsPure; }
|
||||
void setPure(bool P = true) { IsPure = P; }
|
||||
void setPure(bool P = true);
|
||||
|
||||
/// Whether this function is "trivial" in some specialized C++ senses.
|
||||
/// Can only be true for default constructors, copy constructors,
|
||||
@ -1255,9 +1421,6 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
bool isTrivial() const { return IsTrivial; }
|
||||
void setTrivial(bool IT) { IsTrivial = IT; }
|
||||
|
||||
bool isCopyAssignment() const { return IsCopyAssignment; }
|
||||
void setCopyAssignment(bool CA) { IsCopyAssignment = CA; }
|
||||
|
||||
/// Whether falling off this function implicitly returns null/zero.
|
||||
/// If a more specific implicit return value is required, front-ends
|
||||
/// should synthesize the appropriate return statements.
|
||||
@ -1273,7 +1436,6 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
}
|
||||
|
||||
bool hasWrittenPrototype() const { return HasWrittenPrototype; }
|
||||
void setHasWrittenPrototype(bool P) { HasWrittenPrototype = P; }
|
||||
|
||||
/// \brief Whether this function inherited its prototype from a
|
||||
/// previous declaration.
|
||||
@ -1343,7 +1505,9 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
assert(i < getNumParams() && "Illegal param #");
|
||||
return ParamInfo[i];
|
||||
}
|
||||
void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
|
||||
void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
|
||||
setParams(getASTContext(), NewParamInfo, NumParams);
|
||||
}
|
||||
|
||||
/// getMinRequiredArguments - Returns the minimum number of arguments
|
||||
/// needed to call this function. This may be fewer than the number of
|
||||
@ -1361,31 +1525,32 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
}
|
||||
|
||||
StorageClass getStorageClass() const { return StorageClass(SClass); }
|
||||
void setStorageClass(StorageClass SC) {
|
||||
assert(isLegalForFunction(SC));
|
||||
SClass = SC;
|
||||
}
|
||||
void setStorageClass(StorageClass SC);
|
||||
|
||||
StorageClass getStorageClassAsWritten() const {
|
||||
return StorageClass(SClassAsWritten);
|
||||
}
|
||||
void setStorageClassAsWritten(StorageClass SC) {
|
||||
assert(isLegalForFunction(SC));
|
||||
SClassAsWritten = SC;
|
||||
}
|
||||
|
||||
/// \brief Determine whether the "inline" keyword was specified for this
|
||||
/// function.
|
||||
bool isInlineSpecified() const { return IsInline; }
|
||||
bool isInlineSpecified() const { return IsInlineSpecified; }
|
||||
|
||||
/// Set whether the "inline" keyword was specified for this function.
|
||||
void setInlineSpecified(bool I) { IsInline = I; }
|
||||
void setInlineSpecified(bool I) {
|
||||
IsInlineSpecified = I;
|
||||
IsInline = I;
|
||||
}
|
||||
|
||||
/// Flag that this function is implicitly inline.
|
||||
void setImplicitlyInline() {
|
||||
IsInline = true;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this function should be inlined, because it is
|
||||
/// either marked "inline" or is a member function of a C++ class that
|
||||
/// was defined in the class body.
|
||||
bool isInlined() const;
|
||||
|
||||
|
||||
bool isInlineDefinitionExternallyVisible() const;
|
||||
|
||||
/// isOverloadedOperator - Whether this function declaration
|
||||
@ -1432,7 +1597,9 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// \brief Specify that this record is an instantiation of the
|
||||
/// member function FD.
|
||||
void setInstantiationOfMemberFunction(FunctionDecl *FD,
|
||||
TemplateSpecializationKind TSK);
|
||||
TemplateSpecializationKind TSK) {
|
||||
setInstantiationOfMemberFunction(getASTContext(), FD, TSK);
|
||||
}
|
||||
|
||||
/// \brief Retrieves the function template that is described by this
|
||||
/// function declaration.
|
||||
@ -1526,43 +1693,11 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
void *InsertPos,
|
||||
TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
|
||||
const TemplateArgumentListInfo *TemplateArgsAsWritten = 0,
|
||||
SourceLocation PointOfInstantiation = SourceLocation());
|
||||
|
||||
/// \brief Specify that this function declaration is actually a function
|
||||
/// template specialization.
|
||||
///
|
||||
/// \param Template the function template that this function template
|
||||
/// specialization specializes.
|
||||
///
|
||||
/// \param NumTemplateArgs number of template arguments that produced this
|
||||
/// function template specialization from the template.
|
||||
///
|
||||
/// \param TemplateArgs array of template arguments that produced this
|
||||
/// function template specialization from the template.
|
||||
///
|
||||
/// \param TSK the kind of template specialization this is.
|
||||
///
|
||||
/// \param NumTemplateArgsAsWritten number of template arguments that produced
|
||||
/// this function template specialization from the template.
|
||||
///
|
||||
/// \param TemplateArgsAsWritten array of location info for the template
|
||||
/// arguments.
|
||||
///
|
||||
/// \param LAngleLoc location of left angle token.
|
||||
///
|
||||
/// \param RAngleLoc location of right angle token.
|
||||
///
|
||||
/// \param PointOfInstantiation point at which the function template
|
||||
/// specialization was first instantiated.
|
||||
void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
|
||||
unsigned NumTemplateArgs,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
TemplateSpecializationKind TSK,
|
||||
unsigned NumTemplateArgsAsWritten,
|
||||
TemplateArgumentLoc *TemplateArgsAsWritten,
|
||||
SourceLocation LAngleLoc,
|
||||
SourceLocation RAngleLoc,
|
||||
SourceLocation PointOfInstantiation);
|
||||
SourceLocation PointOfInstantiation = SourceLocation()) {
|
||||
setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs,
|
||||
InsertPos, TSK, TemplateArgsAsWritten,
|
||||
PointOfInstantiation);
|
||||
}
|
||||
|
||||
/// \brief Specifies that this function declaration is actually a
|
||||
/// dependent function template specialization.
|
||||
@ -1620,19 +1755,26 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
class FieldDecl : public DeclaratorDecl {
|
||||
// FIXME: This can be packed into the bitfields in Decl.
|
||||
bool Mutable : 1;
|
||||
mutable unsigned CachedFieldIndex : 31;
|
||||
|
||||
Expr *BitWidth;
|
||||
protected:
|
||||
FieldDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
|
||||
Expr *BW, bool Mutable)
|
||||
: DeclaratorDecl(DK, DC, L, Id, T, TInfo), Mutable(Mutable), BitWidth(BW) {
|
||||
: DeclaratorDecl(DK, DC, L, Id, T, TInfo),
|
||||
Mutable(Mutable), CachedFieldIndex(0), BitWidth(BW) {
|
||||
}
|
||||
|
||||
public:
|
||||
static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
static FieldDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id, QualType T,
|
||||
TypeSourceInfo *TInfo, Expr *BW, bool Mutable);
|
||||
|
||||
/// getFieldIndex - Returns the index of this field within its record,
|
||||
/// as appropriate for passing to ASTRecordLayout::getFieldOffset.
|
||||
unsigned getFieldIndex() const;
|
||||
|
||||
/// isMutable - Determines whether this field is mutable (C++ only).
|
||||
bool isMutable() const { return Mutable; }
|
||||
|
||||
@ -1707,6 +1849,45 @@ class EnumConstantDecl : public ValueDecl {
|
||||
friend class StmtIteratorBase;
|
||||
};
|
||||
|
||||
/// IndirectFieldDecl - An instance of this class is created to represent a
|
||||
/// field injected from an anonymous union/struct into the parent scope.
|
||||
/// IndirectFieldDecl are always implicit.
|
||||
class IndirectFieldDecl : public ValueDecl {
|
||||
NamedDecl **Chaining;
|
||||
unsigned ChainingSize;
|
||||
|
||||
IndirectFieldDecl(DeclContext *DC, SourceLocation L,
|
||||
DeclarationName N, QualType T,
|
||||
NamedDecl **CH, unsigned CHS)
|
||||
: ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {}
|
||||
|
||||
public:
|
||||
static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, NamedDecl **CH, unsigned CHS);
|
||||
|
||||
typedef NamedDecl * const *chain_iterator;
|
||||
chain_iterator chain_begin() const { return Chaining; }
|
||||
chain_iterator chain_end() const { return Chaining+ChainingSize; }
|
||||
|
||||
unsigned getChainingSize() const { return ChainingSize; }
|
||||
|
||||
FieldDecl *getAnonField() const {
|
||||
assert(ChainingSize >= 2);
|
||||
return cast<FieldDecl>(Chaining[ChainingSize - 1]);
|
||||
}
|
||||
|
||||
VarDecl *getVarDecl() const {
|
||||
assert(ChainingSize >= 2);
|
||||
return dyn_cast<VarDecl>(*chain_begin());
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const IndirectFieldDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == IndirectField; }
|
||||
friend class ASTDeclReader;
|
||||
};
|
||||
|
||||
/// TypeDecl - Represents a declaration of a type.
|
||||
///
|
||||
@ -1715,7 +1896,7 @@ class TypeDecl : public NamedDecl {
|
||||
/// this TypeDecl. It is a cache maintained by
|
||||
/// ASTContext::getTypedefType, ASTContext::getTagDeclType, and
|
||||
/// ASTContext::getTemplateTypeParmType, and TemplateTypeParmDecl.
|
||||
mutable Type *TypeForDecl;
|
||||
mutable const Type *TypeForDecl;
|
||||
friend class ASTContext;
|
||||
friend class DeclContext;
|
||||
friend class TagDecl;
|
||||
@ -1729,8 +1910,8 @@ class TypeDecl : public NamedDecl {
|
||||
|
||||
public:
|
||||
// Low-level accessor
|
||||
Type *getTypeForDecl() const { return TypeForDecl; }
|
||||
void setTypeForDecl(Type *TD) { TypeForDecl = TD; }
|
||||
const Type *getTypeForDecl() const { return TypeForDecl; }
|
||||
void setTypeForDecl(const Type *TD) { TypeForDecl = TD; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
@ -1820,6 +2001,19 @@ class TagDecl
|
||||
unsigned NumPositiveBits : 8;
|
||||
unsigned NumNegativeBits : 8;
|
||||
|
||||
/// IsScoped - True if this tag declaration is a scoped enumeration. Only
|
||||
/// possible in C++0x mode.
|
||||
bool IsScoped : 1;
|
||||
/// IsScopedUsingClassTag - If this tag declaration is a scoped enum,
|
||||
/// then this is true if the scoped enum was declared using the class
|
||||
/// tag, false if it was declared with the struct tag. No meaning is
|
||||
/// associated if this tag declaration is not a scoped enum.
|
||||
bool IsScopedUsingClassTag : 1;
|
||||
|
||||
/// IsFixed - True if this is an enumeration with fixed underlying type. Only
|
||||
/// possible in C++0x mode.
|
||||
bool IsFixed : 1;
|
||||
|
||||
private:
|
||||
SourceLocation TagKeywordLoc;
|
||||
SourceLocation RBraceLoc;
|
||||
@ -1859,6 +2053,11 @@ class TagDecl
|
||||
typedef Redeclarable<TagDecl> redeclarable_base;
|
||||
virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
|
||||
|
||||
/// @brief Completes the definition of this tag declaration.
|
||||
///
|
||||
/// This is a helper function for derived classes.
|
||||
void completeDefinition();
|
||||
|
||||
public:
|
||||
typedef redeclarable_base::redecl_iterator redecl_iterator;
|
||||
redecl_iterator redecls_begin() const {
|
||||
@ -1923,9 +2122,6 @@ class TagDecl
|
||||
/// where it is in the process of being defined.
|
||||
void startDefinition();
|
||||
|
||||
/// @brief Completes the definition of this tag declaration.
|
||||
void completeDefinition();
|
||||
|
||||
/// getDefinition - Returns the TagDecl that actually defines this
|
||||
/// struct/union/class/enum. When determining whether or not a
|
||||
/// struct/union/class/enum is completely defined, one should use this method
|
||||
@ -2001,7 +2197,19 @@ class EnumDecl : public TagDecl {
|
||||
/// IntegerType - This represent the integer type that the enum corresponds
|
||||
/// to for code generation purposes. Note that the enumerator constants may
|
||||
/// have a different type than this does.
|
||||
QualType IntegerType;
|
||||
///
|
||||
/// If the underlying integer type was explicitly stated in the source
|
||||
/// code, this is a TypeSourceInfo* for that type. Otherwise this type
|
||||
/// was automatically deduced somehow, and this is a Type*.
|
||||
///
|
||||
/// Normally if IsFixed(), this would contain a TypeSourceInfo*, but in
|
||||
/// some cases it won't.
|
||||
///
|
||||
/// The underlying type of an enumeration never has any qualifiers, so
|
||||
/// we can get away with just storing a raw Type*, and thus save an
|
||||
/// extra pointer when TypeSourceInfo is needed.
|
||||
|
||||
llvm::PointerUnion<const Type*, TypeSourceInfo*> IntegerType;
|
||||
|
||||
/// PromotionType - The integer type that values of this type should
|
||||
/// promote to. In C, enumerators are generally of an integer type
|
||||
@ -2022,11 +2230,16 @@ class EnumDecl : public TagDecl {
|
||||
};
|
||||
|
||||
EnumDecl(DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL)
|
||||
IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL,
|
||||
bool Scoped, bool ScopedUsingClassTag, bool Fixed)
|
||||
: TagDecl(Enum, TTK_Enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) {
|
||||
IntegerType = QualType();
|
||||
assert(Scoped || !ScopedUsingClassTag);
|
||||
IntegerType = (const Type*)0;
|
||||
NumNegativeBits = 0;
|
||||
NumPositiveBits = 0;
|
||||
IsScoped = Scoped;
|
||||
IsScopedUsingClassTag = ScopedUsingClassTag;
|
||||
IsFixed = Fixed;
|
||||
}
|
||||
public:
|
||||
EnumDecl *getCanonicalDecl() {
|
||||
@ -2045,7 +2258,9 @@ class EnumDecl : public TagDecl {
|
||||
|
||||
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
SourceLocation TKL, EnumDecl *PrevDecl);
|
||||
SourceLocation TKL, EnumDecl *PrevDecl,
|
||||
bool IsScoped, bool IsScopedUsingClassTag,
|
||||
bool IsFixed);
|
||||
static EnumDecl *Create(ASTContext &C, EmptyShell Empty);
|
||||
|
||||
/// completeDefinition - When created, the EnumDecl corresponds to a
|
||||
@ -2085,10 +2300,25 @@ class EnumDecl : public TagDecl {
|
||||
|
||||
/// getIntegerType - Return the integer type this enum decl corresponds to.
|
||||
/// This returns a null qualtype for an enum forward definition.
|
||||
QualType getIntegerType() const { return IntegerType; }
|
||||
QualType getIntegerType() const {
|
||||
if (!IntegerType)
|
||||
return QualType();
|
||||
if (const Type* T = IntegerType.dyn_cast<const Type*>())
|
||||
return QualType(T, 0);
|
||||
return IntegerType.get<TypeSourceInfo*>()->getType();
|
||||
}
|
||||
|
||||
/// \brief Set the underlying integer type.
|
||||
void setIntegerType(QualType T) { IntegerType = T; }
|
||||
void setIntegerType(QualType T) { IntegerType = T.getTypePtrOrNull(); }
|
||||
|
||||
/// \brief Set the underlying integer type source info.
|
||||
void setIntegerTypeSourceInfo(TypeSourceInfo* TInfo) { IntegerType = TInfo; }
|
||||
|
||||
/// \brief Return the type source info for the underlying integer type,
|
||||
/// if no type source info exists, return 0.
|
||||
TypeSourceInfo* getIntegerTypeSourceInfo() const {
|
||||
return IntegerType.dyn_cast<TypeSourceInfo*>();
|
||||
}
|
||||
|
||||
/// \brief Returns the width in bits requred to store all the
|
||||
/// non-negative enumerators of this enum.
|
||||
@ -2116,6 +2346,27 @@ class EnumDecl : public TagDecl {
|
||||
NumNegativeBits = Num;
|
||||
}
|
||||
|
||||
/// \brief Returns true if this is a C++0x scoped enumeration.
|
||||
bool isScoped() const {
|
||||
return IsScoped;
|
||||
}
|
||||
|
||||
/// \brief Returns true if this is a C++0x scoped enumeration.
|
||||
bool isScopedUsingClassTag() const {
|
||||
return IsScopedUsingClassTag;
|
||||
}
|
||||
|
||||
/// \brief Returns true if this is a C++0x enumeration with fixed underlying
|
||||
/// type.
|
||||
bool isFixed() const {
|
||||
return IsFixed;
|
||||
}
|
||||
|
||||
/// \brief Returns true if this can be considered a complete type.
|
||||
bool isComplete() const {
|
||||
return isDefinition() || isFixed();
|
||||
}
|
||||
|
||||
/// \brief Returns the enumeration (declared within the template)
|
||||
/// from which this enumeration type was instantiated, or NULL if
|
||||
/// this enumeration was not instantiated from any template.
|
||||
@ -2128,6 +2379,8 @@ class EnumDecl : public TagDecl {
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const EnumDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Enum; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
};
|
||||
|
||||
|
||||
@ -2151,17 +2404,24 @@ class RecordDecl : public TagDecl {
|
||||
/// containing an object.
|
||||
bool HasObjectMember : 1;
|
||||
|
||||
/// \brief Whether the field declarations of this record have been loaded
|
||||
/// from external storage. To avoid unnecessary deserialization of
|
||||
/// methods/nested types we allow deserialization of just the fields
|
||||
/// when needed.
|
||||
mutable bool LoadedFieldsFromExternalStorage : 1;
|
||||
friend class DeclContext;
|
||||
|
||||
protected:
|
||||
RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
RecordDecl *PrevDecl, SourceLocation TKL);
|
||||
|
||||
public:
|
||||
static RecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
SourceLocation TKL = SourceLocation(),
|
||||
RecordDecl* PrevDecl = 0);
|
||||
static RecordDecl *Create(ASTContext &C, EmptyShell Empty);
|
||||
static RecordDecl *Create(const ASTContext &C, EmptyShell Empty);
|
||||
|
||||
const RecordDecl *getPreviousDeclaration() const {
|
||||
return cast_or_null<RecordDecl>(TagDecl::getPreviousDeclaration());
|
||||
@ -2190,11 +2450,6 @@ class RecordDecl : public TagDecl {
|
||||
AnonymousStructOrUnion = Anon;
|
||||
}
|
||||
|
||||
ValueDecl *getAnonymousStructOrUnionObject();
|
||||
const ValueDecl *getAnonymousStructOrUnionObject() const {
|
||||
return const_cast<RecordDecl*>(this)->getAnonymousStructOrUnionObject();
|
||||
}
|
||||
|
||||
bool hasObjectMember() const { return HasObjectMember; }
|
||||
void setHasObjectMember (bool val) { HasObjectMember = val; }
|
||||
|
||||
@ -2229,11 +2484,10 @@ class RecordDecl : public TagDecl {
|
||||
// data members, functions, constructors, destructors, etc.
|
||||
typedef specific_decl_iterator<FieldDecl> field_iterator;
|
||||
|
||||
field_iterator field_begin() const {
|
||||
return field_iterator(decls_begin());
|
||||
}
|
||||
field_iterator field_begin() const;
|
||||
|
||||
field_iterator field_end() const {
|
||||
return field_iterator(decls_end());
|
||||
return field_iterator(decl_iterator());
|
||||
}
|
||||
|
||||
// field_empty - Whether there are any fields (non-static data
|
||||
@ -2244,13 +2498,17 @@ class RecordDecl : public TagDecl {
|
||||
|
||||
/// completeDefinition - Notes that the definition of this type is
|
||||
/// now complete.
|
||||
void completeDefinition();
|
||||
virtual void completeDefinition();
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const RecordDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstRecord && K <= lastRecord;
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Deserialize just the fields.
|
||||
void LoadFieldsFromExternalStorage() const;
|
||||
};
|
||||
|
||||
class FileScopeAsmDecl : public Decl {
|
||||
@ -2275,8 +2533,49 @@ class FileScopeAsmDecl : public Decl {
|
||||
/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body }
|
||||
///
|
||||
class BlockDecl : public Decl, public DeclContext {
|
||||
public:
|
||||
/// A class which contains all the information about a particular
|
||||
/// captured value.
|
||||
class Capture {
|
||||
enum {
|
||||
flag_isByRef = 0x1,
|
||||
flag_isNested = 0x2
|
||||
};
|
||||
|
||||
/// The variable being captured.
|
||||
llvm::PointerIntPair<VarDecl*, 2> VariableAndFlags;
|
||||
|
||||
/// The copy expression, expressed in terms of a DeclRef (or
|
||||
/// BlockDeclRef) to the captured variable. Only required if the
|
||||
/// variable has a C++ class type.
|
||||
Expr *CopyExpr;
|
||||
|
||||
public:
|
||||
Capture(VarDecl *variable, bool byRef, bool nested, Expr *copy)
|
||||
: VariableAndFlags(variable,
|
||||
(byRef ? flag_isByRef : 0) | (nested ? flag_isNested : 0)),
|
||||
CopyExpr(copy) {}
|
||||
|
||||
/// The variable being captured.
|
||||
VarDecl *getVariable() const { return VariableAndFlags.getPointer(); }
|
||||
|
||||
/// Whether this is a "by ref" capture, i.e. a capture of a __block
|
||||
/// variable.
|
||||
bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; }
|
||||
|
||||
/// Whether this is a nested capture, i.e. the variable captured
|
||||
/// is not from outside the immediately enclosing function/block.
|
||||
bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; }
|
||||
|
||||
bool hasCopyExpr() const { return CopyExpr != 0; }
|
||||
Expr *getCopyExpr() const { return CopyExpr; }
|
||||
void setCopyExpr(Expr *e) { CopyExpr = e; }
|
||||
};
|
||||
|
||||
private:
|
||||
// FIXME: This can be packed into the bitfields in Decl.
|
||||
bool IsVariadic : 1;
|
||||
bool CapturesCXXThis : 1;
|
||||
/// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal
|
||||
/// parameters of this function. This is null if a prototype or if there are
|
||||
/// no formals.
|
||||
@ -2286,11 +2585,15 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
Stmt *Body;
|
||||
TypeSourceInfo *SignatureAsWritten;
|
||||
|
||||
Capture *Captures;
|
||||
unsigned NumCaptures;
|
||||
|
||||
protected:
|
||||
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
|
||||
: Decl(Block, DC, CaretLoc), DeclContext(Block),
|
||||
IsVariadic(false), ParamInfo(0), NumParams(0), Body(0),
|
||||
SignatureAsWritten(0) {}
|
||||
IsVariadic(false), CapturesCXXThis(false),
|
||||
ParamInfo(0), NumParams(0), Body(0),
|
||||
SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
|
||||
|
||||
public:
|
||||
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
|
||||
@ -2319,7 +2622,7 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
param_const_iterator param_begin() const { return ParamInfo; }
|
||||
param_const_iterator param_end() const { return ParamInfo+param_size(); }
|
||||
|
||||
unsigned getNumParams() const;
|
||||
unsigned getNumParams() const { return NumParams; }
|
||||
const ParmVarDecl *getParamDecl(unsigned i) const {
|
||||
assert(i < getNumParams() && "Illegal param #");
|
||||
return ParamInfo[i];
|
||||
@ -2330,6 +2633,30 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
}
|
||||
void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
|
||||
|
||||
/// hasCaptures - True if this block (or its nested blocks) captures
|
||||
/// anything of local storage from its enclosing scopes.
|
||||
bool hasCaptures() const { return NumCaptures != 0 || CapturesCXXThis; }
|
||||
|
||||
/// getNumCaptures - Returns the number of captured variables.
|
||||
/// Does not include an entry for 'this'.
|
||||
unsigned getNumCaptures() const { return NumCaptures; }
|
||||
|
||||
typedef const Capture *capture_iterator;
|
||||
typedef const Capture *capture_const_iterator;
|
||||
capture_iterator capture_begin() { return Captures; }
|
||||
capture_iterator capture_end() { return Captures + NumCaptures; }
|
||||
capture_const_iterator capture_begin() const { return Captures; }
|
||||
capture_const_iterator capture_end() const { return Captures + NumCaptures; }
|
||||
|
||||
bool capturesCXXThis() const { return CapturesCXXThis; }
|
||||
|
||||
void setCaptures(ASTContext &Context,
|
||||
const Capture *begin,
|
||||
const Capture *end,
|
||||
bool capturesCXXThis);
|
||||
|
||||
virtual SourceRange getSourceRange() const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const BlockDecl *D) { return true; }
|
||||
@ -2350,6 +2677,32 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
return DB;
|
||||
}
|
||||
|
||||
template<typename decl_type>
|
||||
void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
|
||||
// Note: This routine is implemented here because we need both NamedDecl
|
||||
// and Redeclarable to be defined.
|
||||
|
||||
decl_type *First;
|
||||
|
||||
if (PrevDecl) {
|
||||
// Point to previous. Make sure that this is actually the most recent
|
||||
// redeclaration, or we can build invalid chains. If the most recent
|
||||
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
|
||||
RedeclLink = PreviousDeclLink(llvm::cast<decl_type>(
|
||||
PrevDecl->getMostRecentDeclaration()));
|
||||
First = PrevDecl->getFirstDeclaration();
|
||||
assert(First->RedeclLink.NextIsLatest() && "Expected first");
|
||||
} else {
|
||||
// Make this first.
|
||||
First = static_cast<decl_type*>(this);
|
||||
}
|
||||
|
||||
// First one will point to this one as latest.
|
||||
First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
|
||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(static_cast<decl_type*>(this)))
|
||||
ND->ClearLinkageCache();
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -43,6 +43,7 @@ class DeclarationName;
|
||||
class CompoundStmt;
|
||||
class StoredDeclsMap;
|
||||
class DependentDiagnostic;
|
||||
class ASTMutationListener;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
@ -197,25 +198,25 @@ class Decl {
|
||||
return DeclCtx.get<DeclContext*>();
|
||||
}
|
||||
|
||||
/// Loc - The location that this decl.
|
||||
/// Loc - The location of this decl.
|
||||
SourceLocation Loc;
|
||||
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Kind DeclKind : 8;
|
||||
unsigned DeclKind : 8;
|
||||
|
||||
/// InvalidDecl - This indicates a semantic error occurred.
|
||||
unsigned int InvalidDecl : 1;
|
||||
unsigned InvalidDecl : 1;
|
||||
|
||||
/// HasAttrs - This indicates whether the decl has attributes or not.
|
||||
unsigned int HasAttrs : 1;
|
||||
unsigned HasAttrs : 1;
|
||||
|
||||
/// Implicit - Whether this declaration was implicitly generated by
|
||||
/// the implementation rather than explicitly written by the user.
|
||||
bool Implicit : 1;
|
||||
unsigned Implicit : 1;
|
||||
|
||||
/// \brief Whether this declaration was "used", meaning that a definition is
|
||||
/// required.
|
||||
bool Used : 1;
|
||||
unsigned Used : 1;
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
@ -227,17 +228,24 @@ class Decl {
|
||||
unsigned PCHLevel : 2;
|
||||
|
||||
/// ChangedAfterLoad - if this declaration has changed since being loaded
|
||||
bool ChangedAfterLoad : 1;
|
||||
unsigned ChangedAfterLoad : 1;
|
||||
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 15;
|
||||
unsigned IdentifierNamespace : 12;
|
||||
|
||||
/// \brief Whether the \c CachedLinkage field is active.
|
||||
///
|
||||
/// This field is only valid for NamedDecls subclasses.
|
||||
mutable unsigned HasCachedLinkage : 1;
|
||||
|
||||
/// \brief If \c HasCachedLinkage, the linkage of this declaration.
|
||||
///
|
||||
/// This field is only valid for NamedDecls subclasses.
|
||||
mutable unsigned CachedLinkage : 2;
|
||||
|
||||
|
||||
private:
|
||||
#ifndef NDEBUG
|
||||
void CheckAccessDeclContext() const;
|
||||
#else
|
||||
void CheckAccessDeclContext() const { }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
@ -246,7 +254,9 @@ class Decl {
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false),
|
||||
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)) {
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
{
|
||||
if (Decl::CollectingStats()) add(DK);
|
||||
}
|
||||
|
||||
@ -254,7 +264,9 @@ class Decl {
|
||||
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false),
|
||||
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)) {
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
{
|
||||
if (Decl::CollectingStats()) add(DK);
|
||||
}
|
||||
|
||||
@ -272,7 +284,7 @@ class Decl {
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
Kind getKind() const { return DeclKind; }
|
||||
Kind getKind() const { return static_cast<Kind>(DeclKind); }
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
Decl *getNextDeclInContext() { return NextDeclInContext; }
|
||||
@ -298,17 +310,21 @@ class Decl {
|
||||
|
||||
void setAccess(AccessSpecifier AS) {
|
||||
Access = AS;
|
||||
#ifndef NDEBUG
|
||||
CheckAccessDeclContext();
|
||||
#endif
|
||||
}
|
||||
|
||||
AccessSpecifier getAccess() const {
|
||||
#ifndef NDEBUG
|
||||
CheckAccessDeclContext();
|
||||
#endif
|
||||
return AccessSpecifier(Access);
|
||||
}
|
||||
|
||||
bool hasAttrs() const { return HasAttrs; }
|
||||
void setAttrs(const AttrVec& Attrs);
|
||||
AttrVec& getAttrs() {
|
||||
AttrVec &getAttrs() {
|
||||
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
|
||||
}
|
||||
const AttrVec &getAttrs() const;
|
||||
@ -551,6 +567,9 @@ class Decl {
|
||||
/// template parameter pack.
|
||||
bool isTemplateParameterPack() const;
|
||||
|
||||
/// \brief Whether this declaration is a parameter pack.
|
||||
bool isParameterPack() const;
|
||||
|
||||
/// \brief Whether this declaration is a function or function template.
|
||||
bool isFunctionOrFunctionTemplate() const;
|
||||
|
||||
@ -621,10 +640,14 @@ class Decl {
|
||||
llvm::raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0);
|
||||
void dump() const;
|
||||
void dumpXML() const;
|
||||
void dumpXML(llvm::raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
const Attr *getAttrsImpl() const;
|
||||
|
||||
protected:
|
||||
ASTMutationListener *getASTMutationListener() const;
|
||||
};
|
||||
|
||||
/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when
|
||||
@ -681,23 +704,24 @@ class DeclContextLookupConstResult
|
||||
///
|
||||
class DeclContext {
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Decl::Kind DeclKind : 8;
|
||||
unsigned DeclKind : 8;
|
||||
|
||||
/// \brief Whether this declaration context also has some external
|
||||
/// storage that contains additional declarations that are lexically
|
||||
/// part of this context.
|
||||
mutable bool ExternalLexicalStorage : 1;
|
||||
mutable unsigned ExternalLexicalStorage : 1;
|
||||
|
||||
/// \brief Whether this declaration context also has some external
|
||||
/// storage that contains additional declarations that are visible
|
||||
/// in this context.
|
||||
mutable bool ExternalVisibleStorage : 1;
|
||||
mutable unsigned ExternalVisibleStorage : 1;
|
||||
|
||||
/// \brief Pointer to the data structure used to lookup declarations
|
||||
/// within this context (or a DependentStoredDeclsMap if this is a
|
||||
/// dependent context).
|
||||
mutable StoredDeclsMap *LookupPtr;
|
||||
|
||||
protected:
|
||||
/// FirstDecl - The first declaration stored within this declaration
|
||||
/// context.
|
||||
mutable Decl *FirstDecl;
|
||||
@ -710,7 +734,12 @@ class DeclContext {
|
||||
|
||||
friend class ExternalASTSource;
|
||||
|
||||
protected:
|
||||
/// \brief Build up a chain of declarations.
|
||||
///
|
||||
/// \returns the first/last pair of declarations.
|
||||
static std::pair<Decl *, Decl *>
|
||||
BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls);
|
||||
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), ExternalLexicalStorage(false),
|
||||
ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
|
||||
@ -720,7 +749,7 @@ class DeclContext {
|
||||
~DeclContext();
|
||||
|
||||
Decl::Kind getDeclKind() const {
|
||||
return DeclKind;
|
||||
return static_cast<Decl::Kind>(DeclKind);
|
||||
}
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
@ -807,6 +836,10 @@ class DeclContext {
|
||||
/// C++0x scoped enums), and C++ linkage specifications.
|
||||
bool isTransparentContext() const;
|
||||
|
||||
/// \brief Determines whether this context is, or is nested within,
|
||||
/// a C++ extern "C" linkage spec.
|
||||
bool isExternCContext() const;
|
||||
|
||||
/// \brief Determine whether this declaration context is equivalent
|
||||
/// to the declaration context DC.
|
||||
bool Equals(const DeclContext *DC) const {
|
||||
|
@ -35,6 +35,7 @@ class CXXMethodDecl;
|
||||
class CXXRecordDecl;
|
||||
class CXXMemberLookupCriteria;
|
||||
class CXXFinalOverriderMap;
|
||||
class CXXIndirectPrimaryBaseSet;
|
||||
class FriendDecl;
|
||||
|
||||
/// \brief Represents any kind of function declaration, whether it is a
|
||||
@ -112,6 +113,8 @@ class AccessSpecDecl : public Decl {
|
||||
: Decl(AccessSpec, DC, ASLoc), ColonLoc(ColonLoc) {
|
||||
setAccess(AS);
|
||||
}
|
||||
AccessSpecDecl(EmptyShell Empty)
|
||||
: Decl(AccessSpec, Empty) { }
|
||||
public:
|
||||
/// getAccessSpecifierLoc - The location of the access specifier.
|
||||
SourceLocation getAccessSpecifierLoc() const { return getLocation(); }
|
||||
@ -132,6 +135,9 @@ class AccessSpecDecl : public Decl {
|
||||
SourceLocation ColonLoc) {
|
||||
return new (C) AccessSpecDecl(AS, DC, ASLoc, ColonLoc);
|
||||
}
|
||||
static AccessSpecDecl *Create(ASTContext &C, EmptyShell Empty) {
|
||||
return new (C) AccessSpecDecl(Empty);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
@ -162,6 +168,10 @@ class CXXBaseSpecifier {
|
||||
/// specifier (if present).
|
||||
SourceRange Range;
|
||||
|
||||
/// \brief The source location of the ellipsis, if this is a pack
|
||||
/// expansion.
|
||||
SourceLocation EllipsisLoc;
|
||||
|
||||
/// Virtual - Whether this is a virtual base class or not.
|
||||
bool Virtual : 1;
|
||||
|
||||
@ -177,6 +187,10 @@ class CXXBaseSpecifier {
|
||||
/// VC++ bug.
|
||||
unsigned Access : 2;
|
||||
|
||||
/// InheritConstructors - Whether the class contains a using declaration
|
||||
/// to inherit the named class's constructors.
|
||||
bool InheritConstructors : 1;
|
||||
|
||||
/// BaseTypeInfo - The type of the base class. This will be a class or struct
|
||||
/// (or a typedef of such). The source code range does not include the
|
||||
/// "virtual" or access specifier.
|
||||
@ -186,8 +200,9 @@ class CXXBaseSpecifier {
|
||||
CXXBaseSpecifier() { }
|
||||
|
||||
CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A,
|
||||
TypeSourceInfo *TInfo)
|
||||
: Range(R), Virtual(V), BaseOfClass(BC), Access(A), BaseTypeInfo(TInfo) { }
|
||||
TypeSourceInfo *TInfo, SourceLocation EllipsisLoc)
|
||||
: Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC),
|
||||
Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) { }
|
||||
|
||||
/// getSourceRange - Retrieves the source range that contains the
|
||||
/// entire base specifier.
|
||||
@ -201,6 +216,22 @@ class CXXBaseSpecifier {
|
||||
/// with the 'class' keyword (vs. one declared with the 'struct' keyword).
|
||||
bool isBaseOfClass() const { return BaseOfClass; }
|
||||
|
||||
/// \brief Determine whether this base specifier is a pack expansion.
|
||||
bool isPackExpansion() const { return EllipsisLoc.isValid(); }
|
||||
|
||||
/// \brief Determine whether this base class's constructors get inherited.
|
||||
bool getInheritConstructors() const { return InheritConstructors; }
|
||||
|
||||
/// \brief Set that this base class's constructors should be inherited.
|
||||
void setInheritConstructors(bool Inherit = true) {
|
||||
InheritConstructors = Inherit;
|
||||
}
|
||||
|
||||
/// \brief For a pack expansion, determine the location of the ellipsis.
|
||||
SourceLocation getEllipsisLoc() const {
|
||||
return EllipsisLoc;
|
||||
}
|
||||
|
||||
/// getAccessSpecifier - Returns the access specifier for this base
|
||||
/// specifier. This is the actual base specifier as used for
|
||||
/// semantic analysis, so the result can never be AS_none. To
|
||||
@ -336,20 +367,20 @@ class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
/// \brief Whether we have already declared a destructor within the class.
|
||||
bool DeclaredDestructor : 1;
|
||||
|
||||
/// Bases - Base classes of this class.
|
||||
/// FIXME: This is wasted space for a union.
|
||||
CXXBaseSpecifier *Bases;
|
||||
|
||||
/// NumBases - The number of base class specifiers in Bases.
|
||||
unsigned NumBases;
|
||||
|
||||
/// VBases - direct and indirect virtual base classes of this class.
|
||||
CXXBaseSpecifier *VBases;
|
||||
|
||||
|
||||
/// NumVBases - The number of virtual base class specifiers in VBases.
|
||||
unsigned NumVBases;
|
||||
|
||||
/// Bases - Base classes of this class.
|
||||
/// FIXME: This is wasted space for a union.
|
||||
LazyCXXBaseSpecifiersPtr Bases;
|
||||
|
||||
/// VBases - direct and indirect virtual base classes of this class.
|
||||
LazyCXXBaseSpecifiersPtr VBases;
|
||||
|
||||
/// Conversions - Overload set containing the conversion functions
|
||||
/// of this C++ class (but not its inherited conversion
|
||||
/// functions). Each of the entries in this overload set is a
|
||||
@ -371,6 +402,15 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// in reverse order.
|
||||
FriendDecl *FirstFriend;
|
||||
|
||||
/// \brief Retrieve the set of direct base classes.
|
||||
CXXBaseSpecifier *getBases() const {
|
||||
return Bases.get(Definition->getASTContext().getExternalSource());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the set of virtual base classes.
|
||||
CXXBaseSpecifier *getVBases() const {
|
||||
return VBases.get(Definition->getASTContext().getExternalSource());
|
||||
}
|
||||
} *DefinitionData;
|
||||
|
||||
struct DefinitionData &data() {
|
||||
@ -395,9 +435,17 @@ class CXXRecordDecl : public RecordDecl {
|
||||
llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
|
||||
TemplateOrInstantiation;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void CheckConversionFunction(NamedDecl *D);
|
||||
#endif
|
||||
friend class DeclContext;
|
||||
|
||||
/// \brief Notify the class that member has been added.
|
||||
///
|
||||
/// This routine helps maintain information about the class based on which
|
||||
/// members have been added. It will be invoked by DeclContext::addDecl()
|
||||
/// whenever a member is added to this record.
|
||||
void addedMember(Decl *D);
|
||||
|
||||
void markedVirtualFunctionPure();
|
||||
friend void FunctionDecl::setPure(bool);
|
||||
|
||||
protected:
|
||||
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
|
||||
@ -445,12 +493,12 @@ class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
bool hasDefinition() const { return DefinitionData != 0; }
|
||||
|
||||
static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
SourceLocation TKL = SourceLocation(),
|
||||
CXXRecordDecl* PrevDecl=0,
|
||||
bool DelayTypeCreation = false);
|
||||
static CXXRecordDecl *Create(ASTContext &C, EmptyShell Empty);
|
||||
static CXXRecordDecl *Create(const ASTContext &C, EmptyShell Empty);
|
||||
|
||||
bool isDynamicClass() const {
|
||||
return data().Polymorphic || data().NumVBases != 0;
|
||||
@ -463,8 +511,8 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// class.
|
||||
unsigned getNumBases() const { return data().NumBases; }
|
||||
|
||||
base_class_iterator bases_begin() { return data().Bases; }
|
||||
base_class_const_iterator bases_begin() const { return data().Bases; }
|
||||
base_class_iterator bases_begin() { return data().getBases(); }
|
||||
base_class_const_iterator bases_begin() const { return data().getBases(); }
|
||||
base_class_iterator bases_end() { return bases_begin() + data().NumBases; }
|
||||
base_class_const_iterator bases_end() const {
|
||||
return bases_begin() + data().NumBases;
|
||||
@ -486,8 +534,8 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// class.
|
||||
unsigned getNumVBases() const { return data().NumVBases; }
|
||||
|
||||
base_class_iterator vbases_begin() { return data().VBases; }
|
||||
base_class_const_iterator vbases_begin() const { return data().VBases; }
|
||||
base_class_iterator vbases_begin() { return data().getVBases(); }
|
||||
base_class_const_iterator vbases_begin() const { return data().getVBases(); }
|
||||
base_class_iterator vbases_end() { return vbases_begin() + data().NumVBases; }
|
||||
base_class_const_iterator vbases_end() const {
|
||||
return vbases_begin() + data().NumVBases;
|
||||
@ -553,18 +601,12 @@ class CXXRecordDecl : public RecordDecl {
|
||||
return data().DeclaredDefaultConstructor;
|
||||
}
|
||||
|
||||
/// \brief Note whether this class has already had its default constructor
|
||||
/// implicitly declared or doesn't need one.
|
||||
void setDeclaredDefaultConstructor(bool DDC) {
|
||||
data().DeclaredDefaultConstructor = DDC;
|
||||
}
|
||||
|
||||
/// hasConstCopyConstructor - Determines whether this class has a
|
||||
/// copy constructor that accepts a const-qualified argument.
|
||||
bool hasConstCopyConstructor(ASTContext &Context) const;
|
||||
bool hasConstCopyConstructor(const ASTContext &Context) const;
|
||||
|
||||
/// getCopyConstructor - Returns the copy constructor for this class
|
||||
CXXConstructorDecl *getCopyConstructor(ASTContext &Context,
|
||||
CXXConstructorDecl *getCopyConstructor(const ASTContext &Context,
|
||||
unsigned TypeQuals) const;
|
||||
|
||||
/// \brief Retrieve the copy-assignment operator for this class, if available.
|
||||
@ -579,11 +621,6 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// a unique copy-assignment operator could not be found.
|
||||
CXXMethodDecl *getCopyAssignmentOperator(bool ArgIsConst) const;
|
||||
|
||||
/// addedConstructor - Notify the class that another constructor has
|
||||
/// been added. This routine helps maintain information about the
|
||||
/// class based on which constructors have been added.
|
||||
void addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl);
|
||||
|
||||
/// hasUserDeclaredConstructor - Whether this class has any
|
||||
/// user-declared constructors. When true, a default constructor
|
||||
/// will not be implicitly declared.
|
||||
@ -606,17 +643,6 @@ class CXXRecordDecl : public RecordDecl {
|
||||
return data().DeclaredCopyConstructor;
|
||||
}
|
||||
|
||||
/// \brief Note whether this class has already had its copy constructor
|
||||
/// declared.
|
||||
void setDeclaredCopyConstructor(bool DCC) {
|
||||
data().DeclaredCopyConstructor = DCC;
|
||||
}
|
||||
|
||||
/// addedAssignmentOperator - Notify the class that another assignment
|
||||
/// operator has been added. This routine helps maintain information about the
|
||||
/// class based on which operators have been added.
|
||||
void addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl);
|
||||
|
||||
/// hasUserDeclaredCopyAssignment - Whether this class has a
|
||||
/// user-declared copy assignment operator. When false, a copy
|
||||
/// assigment operator will be implicitly declared.
|
||||
@ -632,12 +658,6 @@ class CXXRecordDecl : public RecordDecl {
|
||||
return data().DeclaredCopyAssignment;
|
||||
}
|
||||
|
||||
/// \brief Note whether this class has already had its copy assignment
|
||||
/// operator declared.
|
||||
void setDeclaredCopyAssignment(bool DCA) {
|
||||
data().DeclaredCopyAssignment = DCA;
|
||||
}
|
||||
|
||||
/// hasUserDeclaredDestructor - Whether this class has a
|
||||
/// user-declared destructor. When false, a destructor will be
|
||||
/// implicitly declared.
|
||||
@ -645,26 +665,12 @@ class CXXRecordDecl : public RecordDecl {
|
||||
return data().UserDeclaredDestructor;
|
||||
}
|
||||
|
||||
/// setUserDeclaredDestructor - Set whether this class has a
|
||||
/// user-declared destructor. If not set by the time the class is
|
||||
/// fully defined, a destructor will be implicitly declared.
|
||||
void setUserDeclaredDestructor(bool UCD) {
|
||||
data().UserDeclaredDestructor = UCD;
|
||||
if (UCD)
|
||||
data().DeclaredDestructor = true;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has had its destructor declared,
|
||||
/// either via the user or via an implicit declaration.
|
||||
///
|
||||
/// This value is used for lazy creation of destructors.
|
||||
bool hasDeclaredDestructor() const { return data().DeclaredDestructor; }
|
||||
|
||||
/// \brief Note whether this class has already had its destructor declared.
|
||||
void setDeclaredDestructor(bool DD) {
|
||||
data().DeclaredDestructor = DD;
|
||||
}
|
||||
|
||||
|
||||
/// getConversions - Retrieve the overload set containing all of the
|
||||
/// conversion functions in this class.
|
||||
UnresolvedSetImpl *getConversionFunctions() {
|
||||
@ -682,13 +688,6 @@ class CXXRecordDecl : public RecordDecl {
|
||||
return getConversionFunctions()->end();
|
||||
}
|
||||
|
||||
/// Replaces a conversion function with a new declaration.
|
||||
///
|
||||
/// Returns true if the old conversion was found.
|
||||
bool replaceConversion(const NamedDecl* Old, NamedDecl *New) {
|
||||
return getConversionFunctions()->replace(Old, New);
|
||||
}
|
||||
|
||||
/// Removes a conversion function from this class. The conversion
|
||||
/// function must currently be a member of this class. Furthermore,
|
||||
/// this class must currently be in the process of being defined.
|
||||
@ -698,105 +697,52 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// in current class; including conversion function templates.
|
||||
const UnresolvedSetImpl *getVisibleConversionFunctions();
|
||||
|
||||
/// addConversionFunction - Registers a conversion function which
|
||||
/// this class declares directly.
|
||||
void addConversionFunction(NamedDecl *Decl) {
|
||||
#ifndef NDEBUG
|
||||
CheckConversionFunction(Decl);
|
||||
#endif
|
||||
|
||||
// We intentionally don't use the decl's access here because it
|
||||
// hasn't been set yet. That's really just a misdesign in Sema.
|
||||
data().Conversions.addDecl(Decl);
|
||||
}
|
||||
|
||||
/// isAggregate - Whether this class is an aggregate (C++
|
||||
/// [dcl.init.aggr]), which is a class with no user-declared
|
||||
/// constructors, no private or protected non-static data members,
|
||||
/// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1).
|
||||
bool isAggregate() const { return data().Aggregate; }
|
||||
|
||||
/// setAggregate - Set whether this class is an aggregate (C++
|
||||
/// [dcl.init.aggr]).
|
||||
void setAggregate(bool Agg) { data().Aggregate = Agg; }
|
||||
|
||||
/// setMethodAsVirtual - Make input method virtual and set the necesssary
|
||||
/// special function bits and other bits accordingly.
|
||||
void setMethodAsVirtual(FunctionDecl *Method);
|
||||
|
||||
/// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class
|
||||
/// that is an aggregate that has no non-static non-POD data members, no
|
||||
/// reference data members, no user-defined copy assignment operator and no
|
||||
/// user-defined destructor.
|
||||
bool isPOD() const { return data().PlainOldData; }
|
||||
|
||||
/// setPOD - Set whether this class is a POD-type (C++ [class]p4).
|
||||
void setPOD(bool POD) { data().PlainOldData = POD; }
|
||||
|
||||
/// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which
|
||||
/// means it has a virtual function, virtual base, data member (other than
|
||||
/// 0-width bit-field) or inherits from a non-empty class. Does NOT include
|
||||
/// a check for union-ness.
|
||||
bool isEmpty() const { return data().Empty; }
|
||||
|
||||
/// Set whether this class is empty (C++0x [meta.unary.prop])
|
||||
void setEmpty(bool Emp) { data().Empty = Emp; }
|
||||
|
||||
/// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]),
|
||||
/// which means that the class contains or inherits a virtual function.
|
||||
bool isPolymorphic() const { return data().Polymorphic; }
|
||||
|
||||
/// setPolymorphic - Set whether this class is polymorphic (C++
|
||||
/// [class.virtual]).
|
||||
void setPolymorphic(bool Poly) { data().Polymorphic = Poly; }
|
||||
|
||||
/// isAbstract - Whether this class is abstract (C++ [class.abstract]),
|
||||
/// which means that the class contains or inherits a pure virtual function.
|
||||
bool isAbstract() const { return data().Abstract; }
|
||||
|
||||
/// setAbstract - Set whether this class is abstract (C++ [class.abstract])
|
||||
void setAbstract(bool Abs) { data().Abstract = Abs; }
|
||||
|
||||
// hasTrivialConstructor - Whether this class has a trivial constructor
|
||||
// (C++ [class.ctor]p5)
|
||||
bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
|
||||
|
||||
// setHasTrivialConstructor - Set whether this class has a trivial constructor
|
||||
// (C++ [class.ctor]p5)
|
||||
void setHasTrivialConstructor(bool TC) { data().HasTrivialConstructor = TC; }
|
||||
|
||||
// hasTrivialCopyConstructor - Whether this class has a trivial copy
|
||||
// constructor (C++ [class.copy]p6)
|
||||
bool hasTrivialCopyConstructor() const {
|
||||
return data().HasTrivialCopyConstructor;
|
||||
}
|
||||
|
||||
// setHasTrivialCopyConstructor - Set whether this class has a trivial
|
||||
// copy constructor (C++ [class.copy]p6)
|
||||
void setHasTrivialCopyConstructor(bool TC) {
|
||||
data().HasTrivialCopyConstructor = TC;
|
||||
}
|
||||
|
||||
// hasTrivialCopyAssignment - Whether this class has a trivial copy
|
||||
// assignment operator (C++ [class.copy]p11)
|
||||
bool hasTrivialCopyAssignment() const {
|
||||
return data().HasTrivialCopyAssignment;
|
||||
}
|
||||
|
||||
// setHasTrivialCopyAssignment - Set whether this class has a
|
||||
// trivial copy assignment operator (C++ [class.copy]p11)
|
||||
void setHasTrivialCopyAssignment(bool TC) {
|
||||
data().HasTrivialCopyAssignment = TC;
|
||||
}
|
||||
|
||||
// hasTrivialDestructor - Whether this class has a trivial destructor
|
||||
// (C++ [class.dtor]p3)
|
||||
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
|
||||
|
||||
// setHasTrivialDestructor - Set whether this class has a trivial destructor
|
||||
// (C++ [class.dtor]p3)
|
||||
void setHasTrivialDestructor(bool TC) { data().HasTrivialDestructor = TC; }
|
||||
|
||||
/// \brief If this record is an instantiation of a member class,
|
||||
/// retrieves the member class from which it was instantiated.
|
||||
///
|
||||
@ -854,9 +800,6 @@ class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
/// \brief Set the kind of specialization or template instantiation this is.
|
||||
void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
|
||||
|
||||
/// getDefaultConstructor - Returns the default constructor for this class
|
||||
CXXConstructorDecl *getDefaultConstructor();
|
||||
|
||||
/// getDestructor - Returns the destructor decl for this class.
|
||||
CXXDestructorDecl *getDestructor() const;
|
||||
@ -880,7 +823,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \param Base the base class we are searching for.
|
||||
///
|
||||
/// \returns true if this class is derived from Base, false otherwise.
|
||||
bool isDerivedFrom(CXXRecordDecl *Base) const;
|
||||
bool isDerivedFrom(const CXXRecordDecl *Base) const;
|
||||
|
||||
/// \brief Determine whether this class is derived from the type \p Base.
|
||||
///
|
||||
@ -898,7 +841,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
///
|
||||
/// \todo add a separate paramaeter to configure IsDerivedFrom, rather than
|
||||
/// tangling input and output in \p Paths
|
||||
bool isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const;
|
||||
bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const;
|
||||
|
||||
/// \brief Determine whether this class is virtually derived from
|
||||
/// the class \p Base.
|
||||
@ -1034,6 +977,9 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// most-derived class in the class hierarchy.
|
||||
void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const;
|
||||
|
||||
/// \brief Get the indirect primary bases for this class.
|
||||
void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const;
|
||||
|
||||
/// viewInheritance - Renders and displays an inheritance diagram
|
||||
/// for this C++ class and all of its base classes (transitively) using
|
||||
/// GraphViz.
|
||||
@ -1048,6 +994,27 @@ class CXXRecordDecl : public RecordDecl {
|
||||
return (PathAccess > DeclAccess ? PathAccess : DeclAccess);
|
||||
}
|
||||
|
||||
/// \brief Indicates that the definition of this class is now complete.
|
||||
virtual void completeDefinition();
|
||||
|
||||
/// \brief Indicates that the definition of this class is now complete,
|
||||
/// and provides a final overrider map to help determine
|
||||
///
|
||||
/// \param FinalOverriders The final overrider map for this class, which can
|
||||
/// be provided as an optimization for abstract-class checking. If NULL,
|
||||
/// final overriders will be computed if they are needed to complete the
|
||||
/// definition.
|
||||
void completeDefinition(CXXFinalOverriderMap *FinalOverriders);
|
||||
|
||||
/// \brief Determine whether this class may end up being abstract, even though
|
||||
/// it is not yet known to be abstract.
|
||||
///
|
||||
/// \returns true if this class is not known to be abstract but has any
|
||||
/// base classes that are abstract. In this case, \c completeDefinition()
|
||||
/// will need to compute final overriders to determine whether the class is
|
||||
/// actually abstract.
|
||||
bool mayBeAbstract() const;
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstCXXRecord && K <= lastCXXRecord;
|
||||
@ -1059,6 +1026,8 @@ class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
friend class ASTReader;
|
||||
friend class ASTWriter;
|
||||
};
|
||||
|
||||
/// CXXMethodDecl - Represents a static or instance method of a
|
||||
@ -1139,6 +1108,20 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
return getType()->getAs<FunctionProtoType>()->getTypeQuals();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the ref-qualifier associated with this method.
|
||||
///
|
||||
/// In the following example, \c f() has an lvalue ref-qualifier, \c g()
|
||||
/// has an rvalue ref-qualifier, and \c h() has no ref-qualifier.
|
||||
/// \code
|
||||
/// struct X {
|
||||
/// void f() &;
|
||||
/// void g() &&;
|
||||
/// void h();
|
||||
/// };
|
||||
RefQualifierKind getRefQualifier() const {
|
||||
return getType()->getAs<FunctionProtoType>()->getRefQualifier();
|
||||
}
|
||||
|
||||
bool hasInlineBody() const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
@ -1149,7 +1132,7 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
}
|
||||
};
|
||||
|
||||
/// CXXBaseOrMemberInitializer - Represents a C++ base or member
|
||||
/// CXXCtorInitializer - Represents a C++ base or member
|
||||
/// initializer, which is part of a constructor initializer that
|
||||
/// initializes one non-static member variable or one base class. For
|
||||
/// example, in the following, both 'A(a)' and 'f(3.14159)' are member
|
||||
@ -1163,37 +1146,20 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
/// B(A& a) : A(a), f(3.14159) { }
|
||||
/// };
|
||||
/// @endcode
|
||||
class CXXBaseOrMemberInitializer {
|
||||
/// \brief Either the base class name (stored as a TypeSourceInfo*) or the
|
||||
/// field being initialized.
|
||||
llvm::PointerUnion<TypeSourceInfo *, FieldDecl *> BaseOrMember;
|
||||
class CXXCtorInitializer {
|
||||
/// \brief Either the base class name (stored as a TypeSourceInfo*), an normal
|
||||
/// field (FieldDecl) or an anonymous field (IndirectFieldDecl*) being
|
||||
/// initialized.
|
||||
llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *>
|
||||
Initializee;
|
||||
|
||||
/// \brief The source location for the field name.
|
||||
SourceLocation MemberLocation;
|
||||
/// \brief The source location for the field name or, for a base initializer
|
||||
/// pack expansion, the location of the ellipsis.
|
||||
SourceLocation MemberOrEllipsisLocation;
|
||||
|
||||
/// \brief The argument used to initialize the base or member, which may
|
||||
/// end up constructing an object (when multiple arguments are involved).
|
||||
Stmt *Init;
|
||||
|
||||
/// \brief Stores either the constructor to call to initialize this base or
|
||||
/// member (a CXXConstructorDecl pointer), or stores the anonymous union of
|
||||
/// which the initialized value is a member.
|
||||
///
|
||||
/// When the value is a FieldDecl pointer, 'BaseOrMember' is class's
|
||||
/// anonymous union data member, this field holds the FieldDecl for the
|
||||
/// member of the anonymous union being initialized.
|
||||
/// @code
|
||||
/// struct X {
|
||||
/// X() : au_i1(123) {}
|
||||
/// union {
|
||||
/// int au_i1;
|
||||
/// float au_f1;
|
||||
/// };
|
||||
/// };
|
||||
/// @endcode
|
||||
/// In above example, BaseOrMember holds the field decl. for anonymous union
|
||||
/// and AnonUnionMember holds field decl for au_i1.
|
||||
FieldDecl *AnonUnionMember;
|
||||
|
||||
/// LParenLoc - Location of the left paren of the ctor-initializer.
|
||||
SourceLocation LParenLoc;
|
||||
@ -1208,6 +1174,7 @@ class CXXBaseOrMemberInitializer {
|
||||
/// IsWritten - Whether or not the initializer is explicitly written
|
||||
/// in the sources.
|
||||
bool IsWritten : 1;
|
||||
|
||||
/// SourceOrderOrNumArrayIndices - If IsWritten is true, then this
|
||||
/// number keeps track of the textual order of this initializer in the
|
||||
/// original sources, counting from 0; otherwise, if IsWritten is false,
|
||||
@ -1215,50 +1182,62 @@ class CXXBaseOrMemberInitializer {
|
||||
/// object in memory.
|
||||
unsigned SourceOrderOrNumArrayIndices : 14;
|
||||
|
||||
CXXBaseOrMemberInitializer(ASTContext &Context,
|
||||
FieldDecl *Member, SourceLocation MemberLoc,
|
||||
SourceLocation L,
|
||||
Expr *Init,
|
||||
SourceLocation R,
|
||||
VarDecl **Indices,
|
||||
unsigned NumIndices);
|
||||
CXXCtorInitializer(ASTContext &Context, FieldDecl *Member,
|
||||
SourceLocation MemberLoc, SourceLocation L, Expr *Init,
|
||||
SourceLocation R, VarDecl **Indices, unsigned NumIndices);
|
||||
|
||||
public:
|
||||
/// CXXBaseOrMemberInitializer - Creates a new base-class initializer.
|
||||
/// CXXCtorInitializer - Creates a new base-class initializer.
|
||||
explicit
|
||||
CXXBaseOrMemberInitializer(ASTContext &Context,
|
||||
TypeSourceInfo *TInfo, bool IsVirtual,
|
||||
SourceLocation L,
|
||||
Expr *Init,
|
||||
SourceLocation R);
|
||||
CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual,
|
||||
SourceLocation L, Expr *Init, SourceLocation R,
|
||||
SourceLocation EllipsisLoc);
|
||||
|
||||
/// CXXBaseOrMemberInitializer - Creates a new member initializer.
|
||||
/// CXXCtorInitializer - Creates a new member initializer.
|
||||
explicit
|
||||
CXXBaseOrMemberInitializer(ASTContext &Context,
|
||||
FieldDecl *Member, SourceLocation MemberLoc,
|
||||
SourceLocation L,
|
||||
Expr *Init,
|
||||
SourceLocation R);
|
||||
CXXCtorInitializer(ASTContext &Context, FieldDecl *Member,
|
||||
SourceLocation MemberLoc, SourceLocation L, Expr *Init,
|
||||
SourceLocation R);
|
||||
|
||||
explicit
|
||||
CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member,
|
||||
SourceLocation MemberLoc, SourceLocation L, Expr *Init,
|
||||
SourceLocation R);
|
||||
|
||||
/// \brief Creates a new member initializer that optionally contains
|
||||
/// array indices used to describe an elementwise initialization.
|
||||
static CXXBaseOrMemberInitializer *Create(ASTContext &Context,
|
||||
FieldDecl *Member,
|
||||
SourceLocation MemberLoc,
|
||||
SourceLocation L,
|
||||
Expr *Init,
|
||||
SourceLocation R,
|
||||
VarDecl **Indices,
|
||||
unsigned NumIndices);
|
||||
static CXXCtorInitializer *Create(ASTContext &Context, FieldDecl *Member,
|
||||
SourceLocation MemberLoc, SourceLocation L,
|
||||
Expr *Init, SourceLocation R,
|
||||
VarDecl **Indices, unsigned NumIndices);
|
||||
|
||||
/// isBaseInitializer - Returns true when this initializer is
|
||||
/// initializing a base class.
|
||||
bool isBaseInitializer() const { return BaseOrMember.is<TypeSourceInfo*>(); }
|
||||
bool isBaseInitializer() const { return Initializee.is<TypeSourceInfo*>(); }
|
||||
|
||||
/// isMemberInitializer - Returns true when this initializer is
|
||||
/// initializing a non-static data member.
|
||||
bool isMemberInitializer() const { return BaseOrMember.is<FieldDecl*>(); }
|
||||
bool isMemberInitializer() const { return Initializee.is<FieldDecl*>(); }
|
||||
|
||||
bool isAnyMemberInitializer() const {
|
||||
return isMemberInitializer() || isIndirectMemberInitializer();
|
||||
}
|
||||
|
||||
bool isIndirectMemberInitializer() const {
|
||||
return Initializee.is<IndirectFieldDecl*>();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this initializer is a pack expansion.
|
||||
bool isPackExpansion() const {
|
||||
return isBaseInitializer() && MemberOrEllipsisLocation.isValid();
|
||||
}
|
||||
|
||||
// \brief For a pack expansion, returns the location of the ellipsis.
|
||||
SourceLocation getEllipsisLoc() const {
|
||||
assert(isPackExpansion() && "Initializer is not a pack expansion");
|
||||
return MemberOrEllipsisLocation;
|
||||
}
|
||||
|
||||
/// If this is a base class initializer, returns the type of the
|
||||
/// base class with location information. Otherwise, returns an NULL
|
||||
/// type location.
|
||||
@ -1267,7 +1246,6 @@ class CXXBaseOrMemberInitializer {
|
||||
/// If this is a base class initializer, returns the type of the base class.
|
||||
/// Otherwise, returns NULL.
|
||||
const Type *getBaseClass() const;
|
||||
Type *getBaseClass();
|
||||
|
||||
/// Returns whether the base is virtual or not.
|
||||
bool isBaseVirtual() const {
|
||||
@ -1278,7 +1256,7 @@ class CXXBaseOrMemberInitializer {
|
||||
|
||||
/// \brief Returns the declarator information for a base class initializer.
|
||||
TypeSourceInfo *getBaseClassInfo() const {
|
||||
return BaseOrMember.dyn_cast<TypeSourceInfo *>();
|
||||
return Initializee.dyn_cast<TypeSourceInfo *>();
|
||||
}
|
||||
|
||||
/// getMember - If this is a member initializer, returns the
|
||||
@ -1286,18 +1264,28 @@ class CXXBaseOrMemberInitializer {
|
||||
/// initialized. Otherwise, returns NULL.
|
||||
FieldDecl *getMember() const {
|
||||
if (isMemberInitializer())
|
||||
return BaseOrMember.get<FieldDecl*>();
|
||||
return Initializee.get<FieldDecl*>();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
FieldDecl *getAnyMember() const {
|
||||
if (isMemberInitializer())
|
||||
return Initializee.get<FieldDecl*>();
|
||||
else if (isIndirectMemberInitializer())
|
||||
return Initializee.get<IndirectFieldDecl*>()->getAnonField();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
IndirectFieldDecl *getIndirectMember() const {
|
||||
if (isIndirectMemberInitializer())
|
||||
return Initializee.get<IndirectFieldDecl*>();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
SourceLocation getMemberLocation() const {
|
||||
return MemberLocation;
|
||||
}
|
||||
|
||||
void setMember(FieldDecl *Member) {
|
||||
assert(isMemberInitializer());
|
||||
BaseOrMember = Member;
|
||||
return MemberOrEllipsisLocation;
|
||||
}
|
||||
|
||||
/// \brief Determine the source location of the initializer.
|
||||
@ -1329,15 +1317,7 @@ class CXXBaseOrMemberInitializer {
|
||||
IsWritten = true;
|
||||
SourceOrderOrNumArrayIndices = static_cast<unsigned>(pos);
|
||||
}
|
||||
|
||||
FieldDecl *getAnonUnionMember() const {
|
||||
return AnonUnionMember;
|
||||
}
|
||||
void setAnonUnionMember(FieldDecl *anonMember) {
|
||||
AnonUnionMember = anonMember;
|
||||
}
|
||||
|
||||
|
||||
SourceLocation getLParenLoc() const { return LParenLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
|
||||
@ -1388,10 +1368,10 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
bool ImplicitlyDefined : 1;
|
||||
|
||||
/// Support for base and member initializers.
|
||||
/// BaseOrMemberInitializers - The arguments used to initialize the base
|
||||
/// CtorInitializers - The arguments used to initialize the base
|
||||
/// or member.
|
||||
CXXBaseOrMemberInitializer **BaseOrMemberInitializers;
|
||||
unsigned NumBaseOrMemberInitializers;
|
||||
CXXCtorInitializer **CtorInitializers;
|
||||
unsigned NumCtorInitializers;
|
||||
|
||||
CXXConstructorDecl(CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
@ -1400,7 +1380,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
: CXXMethodDecl(CXXConstructor, RD, NameInfo, T, TInfo, false,
|
||||
SC_None, isInline),
|
||||
IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false),
|
||||
BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) {
|
||||
CtorInitializers(0), NumCtorInitializers(0) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
@ -1443,37 +1423,54 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
}
|
||||
|
||||
/// init_iterator - Iterates through the member/base initializer list.
|
||||
typedef CXXBaseOrMemberInitializer **init_iterator;
|
||||
typedef CXXCtorInitializer **init_iterator;
|
||||
|
||||
/// init_const_iterator - Iterates through the memberbase initializer list.
|
||||
typedef CXXBaseOrMemberInitializer * const * init_const_iterator;
|
||||
typedef CXXCtorInitializer * const * init_const_iterator;
|
||||
|
||||
/// init_begin() - Retrieve an iterator to the first initializer.
|
||||
init_iterator init_begin() { return BaseOrMemberInitializers; }
|
||||
init_iterator init_begin() { return CtorInitializers; }
|
||||
/// begin() - Retrieve an iterator to the first initializer.
|
||||
init_const_iterator init_begin() const { return BaseOrMemberInitializers; }
|
||||
init_const_iterator init_begin() const { return CtorInitializers; }
|
||||
|
||||
/// init_end() - Retrieve an iterator past the last initializer.
|
||||
init_iterator init_end() {
|
||||
return BaseOrMemberInitializers + NumBaseOrMemberInitializers;
|
||||
return CtorInitializers + NumCtorInitializers;
|
||||
}
|
||||
/// end() - Retrieve an iterator past the last initializer.
|
||||
init_const_iterator init_end() const {
|
||||
return BaseOrMemberInitializers + NumBaseOrMemberInitializers;
|
||||
return CtorInitializers + NumCtorInitializers;
|
||||
}
|
||||
|
||||
typedef std::reverse_iterator<init_iterator> init_reverse_iterator;
|
||||
typedef std::reverse_iterator<init_const_iterator> init_const_reverse_iterator;
|
||||
|
||||
init_reverse_iterator init_rbegin() {
|
||||
return init_reverse_iterator(init_end());
|
||||
}
|
||||
init_const_reverse_iterator init_rbegin() const {
|
||||
return init_const_reverse_iterator(init_end());
|
||||
}
|
||||
|
||||
init_reverse_iterator init_rend() {
|
||||
return init_reverse_iterator(init_begin());
|
||||
}
|
||||
init_const_reverse_iterator init_rend() const {
|
||||
return init_const_reverse_iterator(init_begin());
|
||||
}
|
||||
|
||||
/// getNumArgs - Determine the number of arguments used to
|
||||
/// initialize the member or base.
|
||||
unsigned getNumBaseOrMemberInitializers() const {
|
||||
return NumBaseOrMemberInitializers;
|
||||
unsigned getNumCtorInitializers() const {
|
||||
return NumCtorInitializers;
|
||||
}
|
||||
|
||||
void setNumBaseOrMemberInitializers(unsigned numBaseOrMemberInitializers) {
|
||||
NumBaseOrMemberInitializers = numBaseOrMemberInitializers;
|
||||
void setNumCtorInitializers(unsigned numCtorInitializers) {
|
||||
NumCtorInitializers = numCtorInitializers;
|
||||
}
|
||||
|
||||
void setBaseOrMemberInitializers(CXXBaseOrMemberInitializer ** initializers) {
|
||||
BaseOrMemberInitializers = initializers;
|
||||
void setCtorInitializers(CXXCtorInitializer ** initializers) {
|
||||
CtorInitializers = initializers;
|
||||
}
|
||||
/// isDefaultConstructor - Whether this constructor is a default
|
||||
/// constructor (C++ [class.ctor]p5), which can be used to
|
||||
@ -1502,15 +1499,44 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
return isCopyConstructor(TypeQuals);
|
||||
}
|
||||
|
||||
/// \brief Determine whether this constructor is a move constructor
|
||||
/// (C++0x [class.copy]p3), which can be used to move values of the class.
|
||||
///
|
||||
/// \param TypeQuals If this constructor is a move constructor, will be set
|
||||
/// to the type qualifiers on the referent of the first parameter's type.
|
||||
bool isMoveConstructor(unsigned &TypeQuals) const;
|
||||
|
||||
/// \brief Determine whether this constructor is a move constructor
|
||||
/// (C++0x [class.copy]p3), which can be used to move values of the class.
|
||||
bool isMoveConstructor() const;
|
||||
|
||||
/// \brief Determine whether this is a copy or move constructor.
|
||||
///
|
||||
/// \param TypeQuals Will be set to the type qualifiers on the reference
|
||||
/// parameter, if in fact this is a copy or move constructor.
|
||||
bool isCopyOrMoveConstructor(unsigned &TypeQuals) const;
|
||||
|
||||
/// \brief Determine whether this a copy or move constructor.
|
||||
bool isCopyOrMoveConstructor() const {
|
||||
unsigned Quals;
|
||||
return isCopyOrMoveConstructor(Quals);
|
||||
}
|
||||
|
||||
/// isConvertingConstructor - Whether this constructor is a
|
||||
/// converting constructor (C++ [class.conv.ctor]), which can be
|
||||
/// used for user-defined conversions.
|
||||
bool isConvertingConstructor(bool AllowExplicit) const;
|
||||
|
||||
/// \brief Determine whether this is a member template specialization that
|
||||
/// looks like a copy constructor. Such constructors are never used to copy
|
||||
/// would copy the object to itself. Such constructors are never used to copy
|
||||
/// an object.
|
||||
bool isCopyConstructorLikeSpecialization() const;
|
||||
bool isSpecializationCopyingObject() const;
|
||||
|
||||
/// \brief Get the constructor that this inheriting constructor is based on.
|
||||
const CXXConstructorDecl *getInheritedConstructor() const;
|
||||
|
||||
/// \brief Set the constructor that this inheriting constructor is based on.
|
||||
void setInheritedConstructor(const CXXConstructorDecl *BaseCtor);
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
@ -1542,8 +1568,9 @@ class CXXDestructorDecl : public CXXMethodDecl {
|
||||
FunctionDecl *OperatorDelete;
|
||||
|
||||
CXXDestructorDecl(CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo,
|
||||
QualType T, bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXDestructor, RD, NameInfo, T, /*TInfo=*/0, false,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXDestructor, RD, NameInfo, T, TInfo, false,
|
||||
SC_None, isInline),
|
||||
ImplicitlyDefined(false), OperatorDelete(0) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
@ -1553,7 +1580,8 @@ class CXXDestructorDecl : public CXXMethodDecl {
|
||||
static CXXDestructorDecl *Create(ASTContext& C, EmptyShell Empty);
|
||||
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, bool isInline,
|
||||
QualType T, TypeSourceInfo* TInfo,
|
||||
bool isInline,
|
||||
bool isImplicitlyDeclared);
|
||||
|
||||
/// isImplicitlyDefined - Whether this destructor was implicitly
|
||||
@ -1918,13 +1946,16 @@ class UsingShadowDecl : public NamedDecl {
|
||||
/// The referenced declaration.
|
||||
NamedDecl *Underlying;
|
||||
|
||||
/// The using declaration which introduced this decl.
|
||||
UsingDecl *Using;
|
||||
/// \brief The using declaration which introduced this decl or the next using
|
||||
/// shadow declaration contained in the aforementioned using declaration.
|
||||
NamedDecl *UsingOrNextShadow;
|
||||
friend class UsingDecl;
|
||||
|
||||
UsingShadowDecl(DeclContext *DC, SourceLocation Loc, UsingDecl *Using,
|
||||
NamedDecl *Target)
|
||||
: NamedDecl(UsingShadow, DC, Loc, DeclarationName()),
|
||||
Underlying(Target), Using(Using) {
|
||||
Underlying(Target),
|
||||
UsingOrNextShadow(reinterpret_cast<NamedDecl *>(Using)) {
|
||||
if (Target) {
|
||||
setDeclName(Target->getDeclName());
|
||||
IdentifierNamespace = Target->getIdentifierNamespace();
|
||||
@ -1952,15 +1983,20 @@ class UsingShadowDecl : public NamedDecl {
|
||||
}
|
||||
|
||||
/// \brief Gets the using declaration to which this declaration is tied.
|
||||
UsingDecl *getUsingDecl() const { return Using; }
|
||||
UsingDecl *getUsingDecl() const;
|
||||
|
||||
/// \brief Sets the using declaration that introduces this target
|
||||
/// declaration.
|
||||
void setUsingDecl(UsingDecl* UD) { Using = UD; }
|
||||
/// \brief The next using shadow declaration contained in the shadow decl
|
||||
/// chain of the using declaration which introduced this decl.
|
||||
UsingShadowDecl *getNextUsingShadowDecl() const {
|
||||
return dyn_cast_or_null<UsingShadowDecl>(UsingOrNextShadow);
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const UsingShadowDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Decl::UsingShadow; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// UsingDecl - Represents a C++ using-declaration. For example:
|
||||
@ -1980,10 +2016,9 @@ class UsingDecl : public NamedDecl {
|
||||
/// declaration name embedded in the ValueDecl base class.
|
||||
DeclarationNameLoc DNLoc;
|
||||
|
||||
/// \brief The collection of shadow declarations associated with
|
||||
/// this using declaration. This set can change as a class is
|
||||
/// processed.
|
||||
llvm::SmallPtrSet<UsingShadowDecl*, 8> Shadows;
|
||||
/// \brief The first shadow declaration of the shadow decl chain associated
|
||||
/// with this using declaration.
|
||||
UsingShadowDecl *FirstUsingShadow;
|
||||
|
||||
// \brief Has 'typename' keyword.
|
||||
bool IsTypeName;
|
||||
@ -1993,7 +2028,7 @@ class UsingDecl : public NamedDecl {
|
||||
const DeclarationNameInfo &NameInfo, bool IsTypeNameArg)
|
||||
: NamedDecl(Using, DC, NameInfo.getLoc(), NameInfo.getName()),
|
||||
NestedNameRange(NNR), UsingLocation(UL), TargetNestedName(TargetNNS),
|
||||
DNLoc(NameInfo.getInfo()), IsTypeName(IsTypeNameArg) {
|
||||
DNLoc(NameInfo.getInfo()), FirstUsingShadow(0),IsTypeName(IsTypeNameArg) {
|
||||
}
|
||||
|
||||
public:
|
||||
@ -2031,29 +2066,58 @@ class UsingDecl : public NamedDecl {
|
||||
/// \brief Sets whether the using declaration has 'typename'.
|
||||
void setTypeName(bool TN) { IsTypeName = TN; }
|
||||
|
||||
typedef llvm::SmallPtrSet<UsingShadowDecl*,8>::const_iterator shadow_iterator;
|
||||
shadow_iterator shadow_begin() const { return Shadows.begin(); }
|
||||
shadow_iterator shadow_end() const { return Shadows.end(); }
|
||||
/// \brief Iterates through the using shadow declarations assosiated with
|
||||
/// this using declaration.
|
||||
class shadow_iterator {
|
||||
/// \brief The current using shadow declaration.
|
||||
UsingShadowDecl *Current;
|
||||
|
||||
void addShadowDecl(UsingShadowDecl *S) {
|
||||
assert(S->getUsingDecl() == this);
|
||||
if (!Shadows.insert(S)) {
|
||||
assert(false && "declaration already in set");
|
||||
public:
|
||||
typedef UsingShadowDecl* value_type;
|
||||
typedef UsingShadowDecl* reference;
|
||||
typedef UsingShadowDecl* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
shadow_iterator() : Current(0) { }
|
||||
explicit shadow_iterator(UsingShadowDecl *C) : Current(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
pointer operator->() const { return Current; }
|
||||
|
||||
shadow_iterator& operator++() {
|
||||
Current = Current->getNextUsingShadowDecl();
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
void removeShadowDecl(UsingShadowDecl *S) {
|
||||
assert(S->getUsingDecl() == this);
|
||||
if (!Shadows.erase(S)) {
|
||||
assert(false && "declaration not in set");
|
||||
|
||||
shadow_iterator operator++(int) {
|
||||
shadow_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(shadow_iterator x, shadow_iterator y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
friend bool operator!=(shadow_iterator x, shadow_iterator y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
||||
shadow_iterator shadow_begin() const {
|
||||
return shadow_iterator(FirstUsingShadow);
|
||||
}
|
||||
shadow_iterator shadow_end() const { return shadow_iterator(); }
|
||||
|
||||
/// \brief Return the number of shadowed declarations associated with this
|
||||
/// using declaration.
|
||||
unsigned getNumShadowDecls() const {
|
||||
return Shadows.size();
|
||||
unsigned shadow_size() const {
|
||||
return std::distance(shadow_begin(), shadow_end());
|
||||
}
|
||||
|
||||
void addShadowDecl(UsingShadowDecl *S);
|
||||
void removeShadowDecl(UsingShadowDecl *S);
|
||||
|
||||
static UsingDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceRange NNR, SourceLocation UsingL,
|
||||
NestedNameSpecifier* TargetNNS,
|
||||
@ -2145,6 +2209,9 @@ class UnresolvedUsingValueDecl : public ValueDecl {
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const UnresolvedUsingValueDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == UnresolvedUsingValue; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// UnresolvedUsingTypenameDecl - Represents a dependent using
|
||||
|
@ -43,11 +43,16 @@ class FriendDecl : public Decl {
|
||||
FriendUnion Friend;
|
||||
|
||||
// A pointer to the next friend in the sequence.
|
||||
FriendDecl *NextFriend;
|
||||
LazyDeclPtr NextFriend;
|
||||
|
||||
// Location of the 'friend' specifier.
|
||||
SourceLocation FriendLoc;
|
||||
|
||||
/// True if this 'friend' declaration is unsupported. Eventually we
|
||||
/// will support every possible friend declaration, but for now we
|
||||
/// silently ignore some and set this flag to authorize all access.
|
||||
bool UnsupportedFriend;
|
||||
|
||||
friend class CXXRecordDecl::friend_iterator;
|
||||
friend class CXXRecordDecl;
|
||||
|
||||
@ -55,13 +60,19 @@ class FriendDecl : public Decl {
|
||||
SourceLocation FriendL)
|
||||
: Decl(Decl::Friend, DC, L),
|
||||
Friend(Friend),
|
||||
NextFriend(0),
|
||||
FriendLoc(FriendL) {
|
||||
NextFriend(),
|
||||
FriendLoc(FriendL),
|
||||
UnsupportedFriend(false) {
|
||||
}
|
||||
|
||||
explicit FriendDecl(EmptyShell Empty)
|
||||
: Decl(Decl::Friend, Empty), NextFriend(0) { }
|
||||
: Decl(Decl::Friend, Empty), NextFriend() { }
|
||||
|
||||
FriendDecl *getNextFriend() {
|
||||
return cast_or_null<FriendDecl>(
|
||||
NextFriend.get(getASTContext().getExternalSource()));
|
||||
}
|
||||
|
||||
public:
|
||||
static FriendDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, FriendUnion Friend_,
|
||||
@ -87,6 +98,14 @@ class FriendDecl : public Decl {
|
||||
return FriendLoc;
|
||||
}
|
||||
|
||||
/// Determines if this friend kind is unsupported.
|
||||
bool isUnsupportedFriend() const {
|
||||
return UnsupportedFriend;
|
||||
}
|
||||
void setUnsupportedFriend(bool Unsupported) {
|
||||
UnsupportedFriend = Unsupported;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const FriendDecl *D) { return true; }
|
||||
@ -115,7 +134,7 @@ class CXXRecordDecl::friend_iterator {
|
||||
|
||||
friend_iterator &operator++() {
|
||||
assert(Ptr && "attempt to increment past end of friend list");
|
||||
Ptr = Ptr->NextFriend;
|
||||
Ptr = Ptr->getNextFriend();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
#ifndef LLVM_CLANG_AST_DECLGROUP_H
|
||||
#define LLVM_CLANG_AST_DECLGROUP_H
|
||||
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
@ -28,7 +28,7 @@ class ObjCProtocolDecl;
|
||||
class ObjCCategoryDecl;
|
||||
class ObjCPropertyDecl;
|
||||
class ObjCPropertyImplDecl;
|
||||
class CXXBaseOrMemberInitializer;
|
||||
class CXXCtorInitializer;
|
||||
|
||||
class ObjCListBase {
|
||||
void operator=(const ObjCListBase &); // DO NOT IMPLEMENT
|
||||
@ -437,7 +437,7 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
|
||||
class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
/// TypeForDecl - This indicates the Type object that represents this
|
||||
/// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType
|
||||
mutable Type *TypeForDecl;
|
||||
mutable const Type *TypeForDecl;
|
||||
friend class ASTContext;
|
||||
|
||||
/// Class's super class.
|
||||
@ -449,8 +449,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
/// Protocols reference in both the @interface and class extensions.
|
||||
ObjCList<ObjCProtocolDecl> AllReferencedProtocols;
|
||||
|
||||
/// List of categories defined for this class.
|
||||
/// FIXME: Why is this a linked list??
|
||||
/// \brief List of categories and class extensions defined for this class.
|
||||
///
|
||||
/// Categories are stored as a linked list in the AST, since the categories
|
||||
/// and class extensions come long after the initial interface declaration,
|
||||
/// and we avoid dynamically-resized arrays in the AST whereever possible.
|
||||
ObjCCategoryDecl *CategoryList;
|
||||
|
||||
/// IvarList - List of all ivars defined by this class; including class
|
||||
@ -459,7 +462,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
|
||||
bool ForwardDecl:1; // declared with @class.
|
||||
bool InternalInterface:1; // true - no @interface for @implementation
|
||||
|
||||
|
||||
/// \brief Indicates that the contents of this Objective-C class will be
|
||||
/// completed by the external AST source when required.
|
||||
mutable bool ExternallyCompleted : 1;
|
||||
|
||||
SourceLocation ClassLoc; // location of the class identifier.
|
||||
SourceLocation SuperClassLoc; // location of the super class identifier.
|
||||
SourceLocation EndLoc; // marks the '>', '}', or identifier.
|
||||
@ -467,6 +474,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
|
||||
SourceLocation CLoc, bool FD, bool isInternal);
|
||||
|
||||
void LoadExternalDefinition() const;
|
||||
public:
|
||||
static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation atLoc,
|
||||
@ -474,7 +482,16 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
SourceLocation ClassLoc = SourceLocation(),
|
||||
bool ForwardDecl = false,
|
||||
bool isInternal = false);
|
||||
|
||||
/// \brief Indicate that this Objective-C class is complete, but that
|
||||
/// the external AST source will be responsible for filling in its contents
|
||||
/// when a complete class is required.
|
||||
void setExternallyCompleted();
|
||||
|
||||
const ObjCProtocolList &getReferencedProtocols() const {
|
||||
if (ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return ReferencedProtocols;
|
||||
}
|
||||
|
||||
@ -494,29 +511,47 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
typedef ObjCProtocolList::iterator protocol_iterator;
|
||||
|
||||
protocol_iterator protocol_begin() const {
|
||||
if (ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return ReferencedProtocols.begin();
|
||||
}
|
||||
protocol_iterator protocol_end() const {
|
||||
if (ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return ReferencedProtocols.end();
|
||||
}
|
||||
|
||||
typedef ObjCProtocolList::loc_iterator protocol_loc_iterator;
|
||||
|
||||
protocol_loc_iterator protocol_loc_begin() const {
|
||||
if (ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return ReferencedProtocols.loc_begin();
|
||||
}
|
||||
|
||||
protocol_loc_iterator protocol_loc_end() const {
|
||||
if (ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return ReferencedProtocols.loc_end();
|
||||
}
|
||||
|
||||
typedef ObjCList<ObjCProtocolDecl>::iterator all_protocol_iterator;
|
||||
|
||||
all_protocol_iterator all_referenced_protocol_begin() const {
|
||||
if (ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return AllReferencedProtocols.empty() ? protocol_begin()
|
||||
: AllReferencedProtocols.begin();
|
||||
}
|
||||
all_protocol_iterator all_referenced_protocol_end() const {
|
||||
if (ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return AllReferencedProtocols.empty() ? protocol_end()
|
||||
: AllReferencedProtocols.end();
|
||||
}
|
||||
@ -551,10 +586,22 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
bool isForwardDecl() const { return ForwardDecl; }
|
||||
void setForwardDecl(bool val) { ForwardDecl = val; }
|
||||
|
||||
ObjCInterfaceDecl *getSuperClass() const { return SuperClass; }
|
||||
ObjCInterfaceDecl *getSuperClass() const {
|
||||
if (ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return SuperClass;
|
||||
}
|
||||
|
||||
void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; }
|
||||
|
||||
ObjCCategoryDecl* getCategoryList() const { return CategoryList; }
|
||||
ObjCCategoryDecl* getCategoryList() const {
|
||||
if (ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return CategoryList;
|
||||
}
|
||||
|
||||
void setCategoryList(ObjCCategoryDecl *category) {
|
||||
CategoryList = category;
|
||||
}
|
||||
@ -595,7 +642,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName);
|
||||
|
||||
// Lookup a method in the classes implementation hierarchy.
|
||||
ObjCMethodDecl *lookupPrivateInstanceMethod(const Selector &Sel);
|
||||
ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel, bool Instance=true);
|
||||
|
||||
// Location information, modeled after the Stmt API.
|
||||
SourceLocation getLocStart() const { return getLocation(); } // '@'interface
|
||||
@ -621,8 +668,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
bool RHSIsQualifiedID = false);
|
||||
|
||||
// Low-level accessor
|
||||
Type *getTypeForDecl() const { return TypeForDecl; }
|
||||
void setTypeForDecl(Type *TD) const { TypeForDecl = TD; }
|
||||
const Type *getTypeForDecl() const { return TypeForDecl; }
|
||||
void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; }
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCInterfaceDecl *D) { return true; }
|
||||
@ -991,6 +1038,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
void insertNextClassCategory() {
|
||||
NextClassCategory = ClassInterface->getCategoryList();
|
||||
ClassInterface->setCategoryList(this);
|
||||
ClassInterface->setChangedSinceDeserialization(true);
|
||||
}
|
||||
|
||||
bool IsClassExtension() const { return getIdentifier() == 0; }
|
||||
@ -1168,7 +1216,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
ObjCInterfaceDecl *SuperClass;
|
||||
/// Support for ivar initialization.
|
||||
/// IvarInitializers - The arguments used to initialize the ivars
|
||||
CXXBaseOrMemberInitializer **IvarInitializers;
|
||||
CXXCtorInitializer **IvarInitializers;
|
||||
unsigned NumIvarInitializers;
|
||||
|
||||
/// true of class extension has at least one bitfield ivar.
|
||||
@ -1187,10 +1235,10 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
ObjCInterfaceDecl *superDecl);
|
||||
|
||||
/// init_iterator - Iterates through the ivar initializer list.
|
||||
typedef CXXBaseOrMemberInitializer **init_iterator;
|
||||
typedef CXXCtorInitializer **init_iterator;
|
||||
|
||||
/// init_const_iterator - Iterates through the ivar initializer list.
|
||||
typedef CXXBaseOrMemberInitializer * const * init_const_iterator;
|
||||
typedef CXXCtorInitializer * const * init_const_iterator;
|
||||
|
||||
/// init_begin() - Retrieve an iterator to the first initializer.
|
||||
init_iterator init_begin() { return IvarInitializers; }
|
||||
@ -1215,7 +1263,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
}
|
||||
|
||||
void setIvarInitializers(ASTContext &C,
|
||||
CXXBaseOrMemberInitializer ** initializers,
|
||||
CXXCtorInitializer ** initializers,
|
||||
unsigned numInitializers);
|
||||
|
||||
bool hasSynthBitfield() const { return HasSynthBitfield; }
|
||||
@ -1322,7 +1370,8 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
OBJC_PR_retain = 0x10,
|
||||
OBJC_PR_copy = 0x20,
|
||||
OBJC_PR_nonatomic = 0x40,
|
||||
OBJC_PR_setter = 0x80
|
||||
OBJC_PR_setter = 0x80,
|
||||
OBJC_PR_atomic = 0x100
|
||||
};
|
||||
|
||||
enum SetterKind { Assign, Retain, Copy };
|
||||
@ -1330,8 +1379,8 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
private:
|
||||
SourceLocation AtLoc; // location of @property
|
||||
TypeSourceInfo *DeclType;
|
||||
unsigned PropertyAttributes : 8;
|
||||
unsigned PropertyAttributesAsWritten : 8;
|
||||
unsigned PropertyAttributes : 9;
|
||||
unsigned PropertyAttributesAsWritten : 9;
|
||||
// @required/@optional
|
||||
unsigned PropertyImplementation : 2;
|
||||
|
||||
@ -1429,6 +1478,10 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
return PropertyIvarDecl;
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, getLocation());
|
||||
}
|
||||
|
||||
/// Lookup a property by name in the specified DeclContext.
|
||||
static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC,
|
||||
IdentifierInfo *propertyID);
|
||||
@ -1450,6 +1503,15 @@ class ObjCPropertyImplDecl : public Decl {
|
||||
};
|
||||
private:
|
||||
SourceLocation AtLoc; // location of @synthesize or @dynamic
|
||||
|
||||
/// \brief For @synthesize, the location of the ivar, if it was written in
|
||||
/// the source code.
|
||||
///
|
||||
/// \code
|
||||
/// @synthesize int a = b
|
||||
/// \endcode
|
||||
SourceLocation IvarLoc;
|
||||
|
||||
/// Property declaration being implemented
|
||||
ObjCPropertyDecl *PropertyDecl;
|
||||
|
||||
@ -1466,9 +1528,10 @@ class ObjCPropertyImplDecl : public Decl {
|
||||
ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L,
|
||||
ObjCPropertyDecl *property,
|
||||
Kind PK,
|
||||
ObjCIvarDecl *ivarDecl)
|
||||
ObjCIvarDecl *ivarDecl,
|
||||
SourceLocation ivarLoc)
|
||||
: Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc),
|
||||
PropertyDecl(property), PropertyIvarDecl(ivarDecl),
|
||||
IvarLoc(ivarLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl),
|
||||
GetterCXXConstructor(0), SetterCXXAssignment(0) {
|
||||
assert (PK == Dynamic || PropertyIvarDecl);
|
||||
}
|
||||
@ -1478,11 +1541,11 @@ class ObjCPropertyImplDecl : public Decl {
|
||||
SourceLocation atLoc, SourceLocation L,
|
||||
ObjCPropertyDecl *property,
|
||||
Kind PK,
|
||||
ObjCIvarDecl *ivarDecl);
|
||||
ObjCIvarDecl *ivarDecl,
|
||||
SourceLocation ivarLoc);
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, getLocation());
|
||||
}
|
||||
virtual SourceRange getSourceRange() const;
|
||||
|
||||
SourceLocation getLocStart() const { return AtLoc; }
|
||||
void setAtLoc(SourceLocation Loc) { AtLoc = Loc; }
|
||||
|
||||
@ -1498,7 +1561,13 @@ class ObjCPropertyImplDecl : public Decl {
|
||||
ObjCIvarDecl *getPropertyIvarDecl() const {
|
||||
return PropertyIvarDecl;
|
||||
}
|
||||
void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; }
|
||||
SourceLocation getPropertyIvarDeclLoc() const { return IvarLoc; }
|
||||
|
||||
void setPropertyIvarDecl(ObjCIvarDecl *Ivar,
|
||||
SourceLocation IvarLoc) {
|
||||
PropertyIvarDecl = Ivar;
|
||||
this->IvarLoc = IvarLoc;
|
||||
}
|
||||
|
||||
Expr *getGetterCXXConstructor() const {
|
||||
return GetterCXXConstructor;
|
||||
@ -1517,6 +1586,8 @@ class ObjCPropertyImplDecl : public Decl {
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCPropertyImplDecl *D) { return true; }
|
||||
static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -53,7 +53,7 @@ class TemplateParameterList {
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
public:
|
||||
static TemplateParameterList *Create(ASTContext &C,
|
||||
static TemplateParameterList *Create(const ASTContext &C,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
NamedDecl **Params,
|
||||
@ -85,7 +85,7 @@ class TemplateParameterList {
|
||||
return begin()[Idx];
|
||||
}
|
||||
|
||||
/// \btief Returns the minimum number of arguments needed to form a
|
||||
/// \brief Returns the minimum number of arguments needed to form a
|
||||
/// template specialization. This may be fewer than the number of
|
||||
/// template parameters, if some of the parameters have default
|
||||
/// arguments or if there is a parameter pack.
|
||||
@ -107,101 +107,57 @@ class TemplateParameterList {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A helper class for making template argument lists.
|
||||
class TemplateArgumentListBuilder {
|
||||
TemplateArgument *StructuredArgs;
|
||||
unsigned MaxStructuredArgs;
|
||||
unsigned NumStructuredArgs;
|
||||
|
||||
llvm::SmallVector<TemplateArgument, 4> FlatArgs;
|
||||
unsigned MaxFlatArgs;
|
||||
unsigned NumFlatArgs;
|
||||
|
||||
bool AddingToPack;
|
||||
unsigned PackBeginIndex;
|
||||
|
||||
public:
|
||||
TemplateArgumentListBuilder(const TemplateParameterList *Parameters,
|
||||
unsigned NumTemplateArgs)
|
||||
: StructuredArgs(0), MaxStructuredArgs(Parameters->size()),
|
||||
NumStructuredArgs(0), FlatArgs(0),
|
||||
MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0),
|
||||
AddingToPack(false), PackBeginIndex(0) { }
|
||||
|
||||
void Append(const TemplateArgument &Arg);
|
||||
void BeginPack();
|
||||
void EndPack();
|
||||
|
||||
unsigned flatSize() const { return FlatArgs.size(); }
|
||||
const TemplateArgument *getFlatArguments() const { return FlatArgs.data(); }
|
||||
|
||||
unsigned structuredSize() const {
|
||||
// If we don't have any structured args, just reuse the flat size.
|
||||
if (!StructuredArgs)
|
||||
return flatSize();
|
||||
|
||||
return NumStructuredArgs;
|
||||
}
|
||||
const TemplateArgument *getStructuredArguments() const {
|
||||
// If we don't have any structured args, just reuse the flat args.
|
||||
if (!StructuredArgs)
|
||||
return getFlatArguments();
|
||||
|
||||
return StructuredArgs;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A template argument list.
|
||||
///
|
||||
/// FIXME: In the future, this class will be extended to support
|
||||
/// variadic templates and member templates, which will make some of
|
||||
/// the function names below make more sense.
|
||||
class TemplateArgumentList {
|
||||
/// \brief The template argument list.
|
||||
///
|
||||
/// The integer value will be non-zero to indicate that this
|
||||
/// template argument list does own the pointer.
|
||||
llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments;
|
||||
llvm::PointerIntPair<const TemplateArgument *, 1> Arguments;
|
||||
|
||||
/// \brief The number of template arguments in this template
|
||||
/// argument list.
|
||||
unsigned NumFlatArguments;
|
||||
|
||||
llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments;
|
||||
unsigned NumStructuredArguments;
|
||||
unsigned NumArguments;
|
||||
|
||||
TemplateArgumentList(const TemplateArgumentList &Other); // DO NOT IMPL
|
||||
void operator=(const TemplateArgumentList &Other); // DO NOT IMPL
|
||||
|
||||
TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs,
|
||||
bool Owned)
|
||||
: Arguments(Args, Owned), NumArguments(NumArgs) { }
|
||||
|
||||
public:
|
||||
/// TemplateArgumentList - If this constructor is passed "true" for 'TakeArgs'
|
||||
/// it copies them into a locally new[]'d array. If passed "false", then it
|
||||
/// just references the array passed in. This is only safe if the builder
|
||||
/// outlives it, but saves a copy.
|
||||
TemplateArgumentList(ASTContext &Context,
|
||||
TemplateArgumentListBuilder &Builder,
|
||||
bool TakeArgs);
|
||||
/// \brief Type used to indicate that the template argument list itself is a
|
||||
/// stack object. It does not own its template arguments.
|
||||
enum OnStackType { OnStack };
|
||||
|
||||
/// TemplateArgumentList - It copies the template arguments into a locally
|
||||
/// new[]'d array.
|
||||
TemplateArgumentList(ASTContext &Context,
|
||||
const TemplateArgument *Args, unsigned NumArgs);
|
||||
/// \brief Create a new template argument list that copies the given set of
|
||||
/// template arguments.
|
||||
static TemplateArgumentList *CreateCopy(ASTContext &Context,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs);
|
||||
|
||||
/// Produces a shallow copy of the given template argument list. This
|
||||
/// assumes that the input argument list outlives it. This takes the list as
|
||||
/// a pointer to avoid looking like a copy constructor, since this really
|
||||
/// really isn't safe to use that way.
|
||||
explicit TemplateArgumentList(const TemplateArgumentList *Other);
|
||||
|
||||
TemplateArgumentList() : NumFlatArguments(0), NumStructuredArguments(0) { }
|
||||
|
||||
/// \brief Copies the template arguments into a locally new[]'d array.
|
||||
void init(ASTContext &Context,
|
||||
const TemplateArgument *Args, unsigned NumArgs);
|
||||
/// \brief Construct a new, temporary template argument list on the stack.
|
||||
///
|
||||
/// The template argument list does not own the template arguments
|
||||
/// provided.
|
||||
explicit TemplateArgumentList(OnStackType,
|
||||
const TemplateArgument *Args, unsigned NumArgs)
|
||||
: Arguments(Args, false), NumArguments(NumArgs) { }
|
||||
|
||||
/// \brief Produces a shallow copy of the given template argument list.
|
||||
///
|
||||
/// This operation assumes that the input argument list outlives it.
|
||||
/// This takes the list as a pointer to avoid looking like a copy
|
||||
/// constructor, since this really really isn't safe to use that
|
||||
/// way.
|
||||
explicit TemplateArgumentList(const TemplateArgumentList *Other)
|
||||
: Arguments(Other->data(), false), NumArguments(Other->size()) { }
|
||||
|
||||
/// \brief Retrieve the template argument at a given index.
|
||||
const TemplateArgument &get(unsigned Idx) const {
|
||||
assert(Idx < NumFlatArguments && "Invalid template argument index");
|
||||
return getFlatArgumentList()[Idx];
|
||||
assert(Idx < NumArguments && "Invalid template argument index");
|
||||
return data()[Idx];
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument at a given index.
|
||||
@ -209,15 +165,11 @@ class TemplateArgumentList {
|
||||
|
||||
/// \brief Retrieve the number of template arguments in this
|
||||
/// template argument list.
|
||||
unsigned size() const { return NumFlatArguments; }
|
||||
unsigned size() const { return NumArguments; }
|
||||
|
||||
/// \brief Retrieve the number of template arguments in the
|
||||
/// flattened template argument list.
|
||||
unsigned flat_size() const { return NumFlatArguments; }
|
||||
|
||||
/// \brief Retrieve the flattened template argument list.
|
||||
const TemplateArgument *getFlatArgumentList() const {
|
||||
return FlatArguments.getPointer();
|
||||
/// \brief Retrieve a pointer to the template argument list.
|
||||
const TemplateArgument *data() const {
|
||||
return Arguments.getPointer();
|
||||
}
|
||||
};
|
||||
|
||||
@ -292,7 +244,31 @@ class TemplateDecl : public NamedDecl {
|
||||
/// which is a FunctionDecl that has been explicitly specialization or
|
||||
/// instantiated from a function template.
|
||||
class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
|
||||
FunctionTemplateSpecializationInfo(FunctionDecl *FD,
|
||||
FunctionTemplateDecl *Template,
|
||||
TemplateSpecializationKind TSK,
|
||||
const TemplateArgumentList *TemplateArgs,
|
||||
const TemplateArgumentListInfo *TemplateArgsAsWritten,
|
||||
SourceLocation POI)
|
||||
: Function(FD),
|
||||
Template(Template, TSK - 1),
|
||||
TemplateArguments(TemplateArgs),
|
||||
TemplateArgumentsAsWritten(TemplateArgsAsWritten),
|
||||
PointOfInstantiation(POI) { }
|
||||
|
||||
public:
|
||||
static FunctionTemplateSpecializationInfo *
|
||||
Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
|
||||
TemplateSpecializationKind TSK,
|
||||
const TemplateArgumentList *TemplateArgs,
|
||||
const TemplateArgumentListInfo *TemplateArgsAsWritten,
|
||||
SourceLocation POI) {
|
||||
return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK,
|
||||
TemplateArgs,
|
||||
TemplateArgsAsWritten,
|
||||
POI);
|
||||
}
|
||||
|
||||
/// \brief The function template specialization that this structure
|
||||
/// describes.
|
||||
FunctionDecl *Function;
|
||||
@ -345,8 +321,8 @@ class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, TemplateArguments->getFlatArgumentList(),
|
||||
TemplateArguments->flat_size(),
|
||||
Profile(ID, TemplateArguments->data(),
|
||||
TemplateArguments->size(),
|
||||
Function->getASTContext());
|
||||
}
|
||||
|
||||
@ -441,11 +417,6 @@ class DependentFunctionTemplateSpecializationInfo {
|
||||
return reinterpret_cast<FunctionTemplateDecl*const*>(this+1);
|
||||
}
|
||||
|
||||
const TemplateArgumentLoc *getTemplateArgs() const {
|
||||
return reinterpret_cast<const TemplateArgumentLoc*>(
|
||||
&getTemplates()[getNumTemplates()]);
|
||||
}
|
||||
|
||||
public:
|
||||
DependentFunctionTemplateSpecializationInfo(
|
||||
const UnresolvedSetImpl &Templates,
|
||||
@ -463,6 +434,12 @@ class DependentFunctionTemplateSpecializationInfo {
|
||||
return getTemplates()[I];
|
||||
}
|
||||
|
||||
/// \brief Returns the explicit template arguments that were given.
|
||||
const TemplateArgumentLoc *getTemplateArgs() const {
|
||||
return reinterpret_cast<const TemplateArgumentLoc*>(
|
||||
&getTemplates()[getNumTemplates()]);
|
||||
}
|
||||
|
||||
/// \brief Returns the number of explicit template arguments that were given.
|
||||
unsigned getNumTemplateArgs() const {
|
||||
return d.NumArgs;
|
||||
@ -584,7 +561,7 @@ class RedeclarableTemplateDecl : public TemplateDecl {
|
||||
/// for the common pointer.
|
||||
CommonBase *getCommonPtr();
|
||||
|
||||
virtual CommonBase *newCommon() = 0;
|
||||
virtual CommonBase *newCommon(ASTContext &C) = 0;
|
||||
|
||||
// Construct a template decl with name, parameters, and templated element.
|
||||
RedeclarableTemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
@ -789,19 +766,13 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { }
|
||||
|
||||
CommonBase *newCommon();
|
||||
CommonBase *newCommon(ASTContext &C);
|
||||
|
||||
Common *getCommonPtr() {
|
||||
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
|
||||
}
|
||||
|
||||
friend void FunctionDecl::setFunctionTemplateSpecialization(
|
||||
FunctionTemplateDecl *Template,
|
||||
const TemplateArgumentList *TemplateArgs,
|
||||
void *InsertPos,
|
||||
TemplateSpecializationKind TSK,
|
||||
const TemplateArgumentListInfo *TemplateArgsAsWritten,
|
||||
SourceLocation PointOfInstantiation);
|
||||
friend class FunctionDecl;
|
||||
|
||||
/// \brief Retrieve the set of function template specializations of this
|
||||
/// function template.
|
||||
@ -940,15 +911,15 @@ class TemplateTypeParmDecl : public TypeDecl {
|
||||
bool Typename, QualType Type, bool ParameterPack)
|
||||
: TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
|
||||
InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() {
|
||||
TypeForDecl = Type.getTypePtr();
|
||||
TypeForDecl = Type.getTypePtrOrNull();
|
||||
}
|
||||
|
||||
public:
|
||||
static TemplateTypeParmDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
static TemplateTypeParmDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, unsigned D, unsigned P,
|
||||
IdentifierInfo *Id, bool Typename,
|
||||
bool ParameterPack);
|
||||
static TemplateTypeParmDecl *Create(ASTContext &C, EmptyShell Empty);
|
||||
static TemplateTypeParmDecl *Create(const ASTContext &C, EmptyShell Empty);
|
||||
|
||||
/// \brief Whether this template type parameter was declared with
|
||||
/// the 'typename' keyword. If not, it was declared with the 'class'
|
||||
@ -1014,22 +985,54 @@ class TemplateTypeParmDecl : public TypeDecl {
|
||||
/// template<int Size> class array { };
|
||||
/// @endcode
|
||||
class NonTypeTemplateParmDecl
|
||||
: public VarDecl, protected TemplateParmPosition {
|
||||
: public DeclaratorDecl, protected TemplateParmPosition {
|
||||
/// \brief The default template argument, if any, and whether or not
|
||||
/// it was inherited.
|
||||
llvm::PointerIntPair<Expr*, 1, bool> DefaultArgumentAndInherited;
|
||||
|
||||
// FIXME: Collapse this into TemplateParamPosition; or, just move depth/index
|
||||
// down here to save memory.
|
||||
|
||||
/// \brief Whether this non-type template parameter is a parameter pack.
|
||||
bool ParameterPack;
|
||||
|
||||
/// \brief Whether this non-type template parameter is an "expanded"
|
||||
/// parameter pack, meaning that its type is a pack expansion and we
|
||||
/// already know the set of types that expansion expands to.
|
||||
bool ExpandedParameterPack;
|
||||
|
||||
/// \brief The number of types in an expanded parameter pack.
|
||||
unsigned NumExpandedTypes;
|
||||
|
||||
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
|
||||
unsigned P, IdentifierInfo *Id, QualType T,
|
||||
TypeSourceInfo *TInfo)
|
||||
: VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, SC_None, SC_None),
|
||||
TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false)
|
||||
bool ParameterPack, TypeSourceInfo *TInfo)
|
||||
: DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo),
|
||||
TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false),
|
||||
ParameterPack(ParameterPack), ExpandedParameterPack(false),
|
||||
NumExpandedTypes(0)
|
||||
{ }
|
||||
|
||||
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
|
||||
unsigned P, IdentifierInfo *Id, QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
const QualType *ExpandedTypes,
|
||||
unsigned NumExpandedTypes,
|
||||
TypeSourceInfo **ExpandedTInfos);
|
||||
|
||||
friend class ASTDeclReader;
|
||||
|
||||
public:
|
||||
static NonTypeTemplateParmDecl *
|
||||
Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
|
||||
unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo);
|
||||
Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
|
||||
unsigned P, IdentifierInfo *Id, QualType T, bool ParameterPack,
|
||||
TypeSourceInfo *TInfo);
|
||||
|
||||
static NonTypeTemplateParmDecl *
|
||||
Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
|
||||
unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
|
||||
const QualType *ExpandedTypes, unsigned NumExpandedTypes,
|
||||
TypeSourceInfo **ExpandedTInfos);
|
||||
|
||||
using TemplateParmPosition::getDepth;
|
||||
using TemplateParmPosition::setDepth;
|
||||
@ -1037,6 +1040,9 @@ class NonTypeTemplateParmDecl
|
||||
using TemplateParmPosition::setPosition;
|
||||
using TemplateParmPosition::getIndex;
|
||||
|
||||
SourceLocation getInnerLocStart() const;
|
||||
SourceRange getSourceRange() const;
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const {
|
||||
@ -1071,6 +1077,65 @@ class NonTypeTemplateParmDecl
|
||||
DefaultArgumentAndInherited.setInt(false);
|
||||
}
|
||||
|
||||
/// \brief Whether this parameter is a non-type template parameter pack.
|
||||
///
|
||||
/// If the parameter is a parameter pack, the type may be a
|
||||
/// \c PackExpansionType. In the following example, the \c Dims parameter
|
||||
/// is a parameter pack (whose type is 'unsigned').
|
||||
///
|
||||
/// \code
|
||||
/// template<typename T, unsigned ...Dims> struct multi_array;
|
||||
/// \endcode
|
||||
bool isParameterPack() const { return ParameterPack; }
|
||||
|
||||
/// \brief Whether this parameter is a non-type template parameter pack
|
||||
/// that has different types at different positions.
|
||||
///
|
||||
/// A parameter pack is an expanded parameter pack when the original
|
||||
/// parameter pack's type was itself a pack expansion, and that expansion
|
||||
/// has already been expanded. For example, given:
|
||||
///
|
||||
/// \code
|
||||
/// template<typename ...Types>
|
||||
/// struct X {
|
||||
/// template<Types ...Values>
|
||||
/// struct Y { /* ... */ };
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// The parameter pack \c Values has a \c PackExpansionType as its type,
|
||||
/// which expands \c Types. When \c Types is supplied with template arguments
|
||||
/// by instantiating \c X, the instantiation of \c Values becomes an
|
||||
/// expanded parameter pack. For example, instantiating
|
||||
/// \c X<int, unsigned int> results in \c Values being an expanded parameter
|
||||
/// pack with expansion types \c int and \c unsigned int.
|
||||
///
|
||||
/// The \c getExpansionType() and \c getExpansionTypeSourceInfo() functions
|
||||
/// return the expansion types.
|
||||
bool isExpandedParameterPack() const { return ExpandedParameterPack; }
|
||||
|
||||
/// \brief Retrieves the number of expansion types in an expanded parameter pack.
|
||||
unsigned getNumExpansionTypes() const {
|
||||
assert(ExpandedParameterPack && "Not an expansion parameter pack");
|
||||
return NumExpandedTypes;
|
||||
}
|
||||
|
||||
/// \brief Retrieve a particular expansion type within an expanded parameter
|
||||
/// pack.
|
||||
QualType getExpansionType(unsigned I) const {
|
||||
assert(I < NumExpandedTypes && "Out-of-range expansion type index");
|
||||
void * const *TypesAndInfos = reinterpret_cast<void * const*>(this + 1);
|
||||
return QualType::getFromOpaquePtr(TypesAndInfos[2*I]);
|
||||
}
|
||||
|
||||
/// \brief Retrieve a particular expansion type source info within an
|
||||
/// expanded parameter pack.
|
||||
TypeSourceInfo *getExpansionTypeSourceInfo(unsigned I) const {
|
||||
assert(I < NumExpandedTypes && "Out-of-range expansion type index");
|
||||
void * const *TypesAndInfos = reinterpret_cast<void * const*>(this + 1);
|
||||
return static_cast<TypeSourceInfo *>(TypesAndInfos[2*I+1]);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
|
||||
@ -1092,24 +1157,36 @@ class TemplateTemplateParmDecl
|
||||
/// Whether or not the default argument was inherited.
|
||||
bool DefaultArgumentWasInherited;
|
||||
|
||||
/// \brief Whether this parameter is a parameter pack.
|
||||
bool ParameterPack;
|
||||
|
||||
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
|
||||
unsigned D, unsigned P,
|
||||
unsigned D, unsigned P, bool ParameterPack,
|
||||
IdentifierInfo *Id, TemplateParameterList *Params)
|
||||
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
|
||||
TemplateParmPosition(D, P), DefaultArgument(),
|
||||
DefaultArgumentWasInherited(false)
|
||||
DefaultArgumentWasInherited(false), ParameterPack(ParameterPack)
|
||||
{ }
|
||||
|
||||
public:
|
||||
static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, unsigned D,
|
||||
unsigned P, IdentifierInfo *Id,
|
||||
unsigned P, bool ParameterPack,
|
||||
IdentifierInfo *Id,
|
||||
TemplateParameterList *Params);
|
||||
|
||||
using TemplateParmPosition::getDepth;
|
||||
using TemplateParmPosition::getPosition;
|
||||
using TemplateParmPosition::getIndex;
|
||||
|
||||
/// \brief Whether this template template parameter is a template
|
||||
/// parameter pack.
|
||||
///
|
||||
/// \code
|
||||
/// template<template <class T> ...MetaFunctions> struct Apply;
|
||||
/// \endcode
|
||||
bool isParameterPack() const { return ParameterPack; }
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const {
|
||||
@ -1211,7 +1288,7 @@ class ClassTemplateSpecializationDecl
|
||||
ExplicitSpecializationInfo *ExplicitInfo;
|
||||
|
||||
/// \brief The template arguments used to describe this specialization.
|
||||
TemplateArgumentList TemplateArgs;
|
||||
TemplateArgumentList *TemplateArgs;
|
||||
|
||||
/// \brief The point where this template was instantiated (if any)
|
||||
SourceLocation PointOfInstantiation;
|
||||
@ -1224,7 +1301,8 @@ class ClassTemplateSpecializationDecl
|
||||
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
|
||||
DeclContext *DC, SourceLocation L,
|
||||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgumentListBuilder &Builder,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
ClassTemplateSpecializationDecl *PrevDecl);
|
||||
|
||||
explicit ClassTemplateSpecializationDecl(Kind DK);
|
||||
@ -1233,7 +1311,8 @@ class ClassTemplateSpecializationDecl
|
||||
static ClassTemplateSpecializationDecl *
|
||||
Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation L,
|
||||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgumentListBuilder &Builder,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
ClassTemplateSpecializationDecl *PrevDecl);
|
||||
static ClassTemplateSpecializationDecl *
|
||||
Create(ASTContext &Context, EmptyShell Empty);
|
||||
@ -1259,15 +1338,7 @@ class ClassTemplateSpecializationDecl
|
||||
/// \brief Retrieve the template arguments of the class template
|
||||
/// specialization.
|
||||
const TemplateArgumentList &getTemplateArgs() const {
|
||||
return TemplateArgs;
|
||||
}
|
||||
|
||||
/// \brief Initialize the template arguments of the class template
|
||||
/// specialization.
|
||||
void initTemplateArgs(TemplateArgument *Args, unsigned NumArgs) {
|
||||
assert(TemplateArgs.flat_size() == 0 &&
|
||||
"Template arguments already initialized!");
|
||||
TemplateArgs.init(getASTContext(), Args, NumArgs);
|
||||
return *TemplateArgs;
|
||||
}
|
||||
|
||||
/// \brief Determine the kind of specialization that this
|
||||
@ -1357,18 +1428,6 @@ class ClassTemplateSpecializationDecl
|
||||
SpecializedTemplate = PS;
|
||||
}
|
||||
|
||||
/// \brief Note that this class template specialization is actually an
|
||||
/// instantiation of the given class template partial specialization whose
|
||||
/// template arguments have been deduced.
|
||||
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
|
||||
TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs) {
|
||||
ASTContext &Ctx = getASTContext();
|
||||
setInstantiationOf(PartialSpec,
|
||||
new (Ctx) TemplateArgumentList(Ctx, TemplateArgs,
|
||||
NumTemplateArgs));
|
||||
}
|
||||
|
||||
/// \brief Note that this class template specialization is an instantiation
|
||||
/// of the given class template.
|
||||
void setInstantiationOf(ClassTemplateDecl *TemplDecl) {
|
||||
@ -1415,8 +1474,7 @@ class ClassTemplateSpecializationDecl
|
||||
SourceLocation getInnerLocStart() const { return getTemplateKeywordLoc(); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(),
|
||||
getASTContext());
|
||||
Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext());
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1440,6 +1498,9 @@ class ClassTemplateSpecializationDecl
|
||||
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
class ClassTemplatePartialSpecializationDecl
|
||||
@ -1469,15 +1530,16 @@ class ClassTemplatePartialSpecializationDecl
|
||||
DeclContext *DC, SourceLocation L,
|
||||
TemplateParameterList *Params,
|
||||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgumentListBuilder &Builder,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
TemplateArgumentLoc *ArgInfos,
|
||||
unsigned NumArgInfos,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl,
|
||||
unsigned SequenceNumber)
|
||||
: ClassTemplateSpecializationDecl(Context,
|
||||
ClassTemplatePartialSpecialization,
|
||||
TK, DC, L, SpecializedTemplate, Builder,
|
||||
PrevDecl),
|
||||
TK, DC, L, SpecializedTemplate,
|
||||
Args, NumArgs, PrevDecl),
|
||||
TemplateParams(Params), ArgsAsWritten(ArgInfos),
|
||||
NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
|
||||
InstantiatedFromMember(0, false) { }
|
||||
@ -1493,7 +1555,8 @@ class ClassTemplatePartialSpecializationDecl
|
||||
Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
|
||||
TemplateParameterList *Params,
|
||||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgumentListBuilder &Builder,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
const TemplateArgumentListInfo &ArgInfos,
|
||||
QualType CanonInjectedType,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl,
|
||||
@ -1512,18 +1575,11 @@ class ClassTemplatePartialSpecializationDecl
|
||||
return TemplateParams;
|
||||
}
|
||||
|
||||
void initTemplateParameters(TemplateParameterList *Params) {
|
||||
assert(TemplateParams == 0 && "TemplateParams already set");
|
||||
TemplateParams = Params;
|
||||
}
|
||||
|
||||
/// Get the template arguments as written.
|
||||
TemplateArgumentLoc *getTemplateArgsAsWritten() const {
|
||||
return ArgsAsWritten;
|
||||
}
|
||||
|
||||
void initTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgInfos);
|
||||
|
||||
/// Get the number of template arguments as written.
|
||||
unsigned getNumTemplateArgsAsWritten() const {
|
||||
return NumArgsAsWritten;
|
||||
@ -1532,8 +1588,7 @@ class ClassTemplatePartialSpecializationDecl
|
||||
/// \brief Get the sequence number for this class template partial
|
||||
/// specialization.
|
||||
unsigned getSequenceNumber() const { return SequenceNumber; }
|
||||
void setSequenceNumber(unsigned N) { SequenceNumber = N; }
|
||||
|
||||
|
||||
/// \brief Retrieve the member class template partial specialization from
|
||||
/// which this particular class template partial specialization was
|
||||
/// instantiated.
|
||||
@ -1617,6 +1672,9 @@ class ClassTemplatePartialSpecializationDecl
|
||||
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// Declaration of a class template.
|
||||
@ -1630,6 +1688,8 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl,
|
||||
/// \brief Data that is common to all of the declarations of a given
|
||||
/// class template.
|
||||
struct Common : CommonBase {
|
||||
Common() : LazySpecializations() { }
|
||||
|
||||
/// \brief The class template specializations for this class
|
||||
/// template, including explicit specializations and instantiations.
|
||||
llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
|
||||
@ -1641,25 +1701,31 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl,
|
||||
|
||||
/// \brief The injected-class-name type for this class template.
|
||||
QualType InjectedClassNameType;
|
||||
|
||||
/// \brief If non-null, points to an array of specializations (including
|
||||
/// partial specializations) known ownly by their external declaration IDs.
|
||||
///
|
||||
/// The first value in the array is the number of of specializations/
|
||||
/// partial specializations that follow.
|
||||
uint32_t *LazySpecializations;
|
||||
};
|
||||
|
||||
/// \brief Load any lazily-loaded specializations from the external source.
|
||||
void LoadLazySpecializations();
|
||||
|
||||
/// \brief Retrieve the set of specializations of this class template.
|
||||
llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations() {
|
||||
return getCommonPtr()->Specializations;
|
||||
}
|
||||
llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations();
|
||||
|
||||
/// \brief Retrieve the set of partial specializations of this class
|
||||
/// template.
|
||||
llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &
|
||||
getPartialSpecializations() {
|
||||
return getCommonPtr()->PartialSpecializations;
|
||||
}
|
||||
getPartialSpecializations();
|
||||
|
||||
ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { }
|
||||
|
||||
CommonBase *newCommon();
|
||||
CommonBase *newCommon(ASTContext &C);
|
||||
|
||||
Common *getCommonPtr() {
|
||||
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
|
||||
@ -1693,9 +1759,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl,
|
||||
|
||||
/// \brief Insert the specified specialization knowing that it is not already
|
||||
/// in. InsertPos must be obtained from findSpecialization.
|
||||
void AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos) {
|
||||
getSpecializations().InsertNode(D, InsertPos);
|
||||
}
|
||||
void AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos);
|
||||
|
||||
ClassTemplateDecl *getCanonicalDecl() {
|
||||
return redeclarable_base::getCanonicalDecl();
|
||||
@ -1729,9 +1793,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl,
|
||||
/// \brief Insert the specified partial specialization knowing that it is not
|
||||
/// already in. InsertPos must be obtained from findPartialSpecialization.
|
||||
void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D,
|
||||
void *InsertPos) {
|
||||
getPartialSpecializations().InsertNode(D, InsertPos);
|
||||
}
|
||||
void *InsertPos);
|
||||
|
||||
/// \brief Return the next partial specialization sequence number.
|
||||
unsigned getNextPartialSpecSequenceNumber() {
|
||||
|
@ -315,7 +315,7 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
|
||||
/// retrieved using its member functions (e.g.,
|
||||
/// getCXXConstructorName).
|
||||
class DeclarationNameTable {
|
||||
ASTContext &Ctx;
|
||||
const ASTContext &Ctx;
|
||||
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
|
||||
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
||||
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
|
||||
@ -324,7 +324,7 @@ class DeclarationNameTable {
|
||||
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
|
||||
|
||||
public:
|
||||
DeclarationNameTable(ASTContext &C);
|
||||
DeclarationNameTable(const ASTContext &C);
|
||||
~DeclarationNameTable();
|
||||
|
||||
/// getIdentifier - Create a declaration name that is a simple
|
||||
@ -402,7 +402,7 @@ struct DeclarationNameLoc {
|
||||
|
||||
DeclarationNameLoc(DeclarationName Name);
|
||||
// FIXME: this should go away once all DNLocs are properly initialized.
|
||||
DeclarationNameLoc() { NamedType.TInfo = 0; }
|
||||
DeclarationNameLoc() { memset((void*) this, 0, sizeof(*this)); }
|
||||
}; // struct DeclarationNameLoc
|
||||
|
||||
|
||||
@ -492,6 +492,10 @@ struct DeclarationNameInfo {
|
||||
LocInfo.CXXLiteralOperatorName.OpNameLoc = Loc.getRawEncoding();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this name contains an unexpanded
|
||||
/// parameter pack.
|
||||
bool containsUnexpandedParameterPack() const;
|
||||
|
||||
/// getAsString - Retrieve the human-readable string for this name.
|
||||
std::string getAsString() const;
|
||||
|
||||
|
82
include/clang/AST/EvaluatedExprVisitor.h
Normal file
82
include/clang/AST/EvaluatedExprVisitor.h
Normal file
@ -0,0 +1,82 @@
|
||||
//===--- EvaluatedExprVisitor.h - Evaluated expression visitor --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the EvaluatedExprVisitor class template, which visits
|
||||
// the potentially-evaluated subexpressions of a potentially-evaluated
|
||||
// expression.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H
|
||||
#define LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H
|
||||
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
|
||||
/// \begin Given a potentially-evaluated expression, this visitor visits all
|
||||
/// of its potentially-evaluated subexpressions, recursively.
|
||||
template<typename ImplClass>
|
||||
class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
|
||||
ASTContext &Context;
|
||||
|
||||
public:
|
||||
explicit EvaluatedExprVisitor(ASTContext &Context) : Context(Context) { }
|
||||
|
||||
// Expressions that have no potentially-evaluated subexpressions (but may have
|
||||
// other sub-expressions).
|
||||
void VisitDeclRefExpr(DeclRefExpr *E) { }
|
||||
void VisitOffsetOfExpr(OffsetOfExpr *E) { }
|
||||
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { }
|
||||
void VisitBlockExpr(BlockExpr *E) { }
|
||||
void VisitCXXUuidofExpr(CXXUuidofExpr *E) { }
|
||||
void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { }
|
||||
|
||||
void VisitMemberExpr(MemberExpr *E) {
|
||||
// Only the base matters.
|
||||
return this->Visit(E->getBase());
|
||||
}
|
||||
|
||||
void VisitChooseExpr(ChooseExpr *E) {
|
||||
// Only the selected subexpression matters; the other one is not evaluated.
|
||||
return this->Visit(E->getChosenSubExpr(Context));
|
||||
}
|
||||
|
||||
void VisitDesignatedInitExpr(DesignatedInitExpr *E) {
|
||||
// Only the actual initializer matters; the designators are all constant
|
||||
// expressions.
|
||||
return this->Visit(E->getInit());
|
||||
}
|
||||
|
||||
void VisitCXXTypeidExpr(CXXTypeidExpr *E) {
|
||||
// typeid(expression) is potentially evaluated when the argument is
|
||||
// a glvalue of polymorphic type. (C++ 5.2.8p2-3)
|
||||
if (!E->isTypeOperand() && E->Classify(Context).isGLValue())
|
||||
if (const RecordType *Record
|
||||
= E->getExprOperand()->getType()->template getAs<RecordType>())
|
||||
if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic())
|
||||
return this->Visit(E->getExprOperand());
|
||||
}
|
||||
|
||||
/// \brief The basis case walks all of the children of the statement or
|
||||
/// expression, assuming they are all potentially evaluated.
|
||||
void VisitStmt(Stmt *S) {
|
||||
for (Stmt::child_range C = S->children(); C; ++C)
|
||||
if (*C)
|
||||
this->Visit(*C);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -14,14 +14,13 @@
|
||||
#ifndef LLVM_CLANG_AST_EXPROBJC_H
|
||||
#define LLVM_CLANG_AST_EXPROBJC_H
|
||||
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
|
||||
namespace clang {
|
||||
class IdentifierInfo;
|
||||
class ASTContext;
|
||||
class ObjCMethodDecl;
|
||||
class ObjCPropertyDecl;
|
||||
|
||||
/// ObjCStringLiteral, used for Objective-C string literals
|
||||
/// i.e. @"foo".
|
||||
@ -30,7 +29,9 @@ class ObjCStringLiteral : public Expr {
|
||||
SourceLocation AtLoc;
|
||||
public:
|
||||
ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L)
|
||||
: Expr(ObjCStringLiteralClass, T, false, false), String(SL), AtLoc(L) {}
|
||||
: Expr(ObjCStringLiteralClass, T, VK_RValue, OK_Ordinary, false, false,
|
||||
false),
|
||||
String(SL), AtLoc(L) {}
|
||||
explicit ObjCStringLiteral(EmptyShell Empty)
|
||||
: Expr(ObjCStringLiteralClass, Empty) {}
|
||||
|
||||
@ -41,7 +42,7 @@ class ObjCStringLiteral : public Expr {
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, String->getLocEnd());
|
||||
}
|
||||
|
||||
@ -51,8 +52,7 @@ class ObjCStringLiteral : public Expr {
|
||||
static bool classof(const ObjCStringLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(&String, &String+1); }
|
||||
};
|
||||
|
||||
/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type
|
||||
@ -64,8 +64,10 @@ class ObjCEncodeExpr : public Expr {
|
||||
public:
|
||||
ObjCEncodeExpr(QualType T, TypeSourceInfo *EncodedType,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCEncodeExprClass, T, EncodedType->getType()->isDependentType(),
|
||||
EncodedType->getType()->isDependentType()),
|
||||
: Expr(ObjCEncodeExprClass, T, VK_LValue, OK_Ordinary,
|
||||
EncodedType->getType()->isDependentType(),
|
||||
EncodedType->getType()->isDependentType(),
|
||||
EncodedType->getType()->containsUnexpandedParameterPack()),
|
||||
EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {}
|
||||
|
||||
explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){}
|
||||
@ -83,7 +85,7 @@ class ObjCEncodeExpr : public Expr {
|
||||
EncodedType = EncType;
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
@ -93,8 +95,7 @@ class ObjCEncodeExpr : public Expr {
|
||||
static bool classof(const ObjCEncodeExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// ObjCSelectorExpr used for @selector in Objective-C.
|
||||
@ -104,8 +105,9 @@ class ObjCSelectorExpr : public Expr {
|
||||
public:
|
||||
ObjCSelectorExpr(QualType T, Selector selInfo,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCSelectorExprClass, T, false, false), SelName(selInfo), AtLoc(at),
|
||||
RParenLoc(rp){}
|
||||
: Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary, false, false,
|
||||
false),
|
||||
SelName(selInfo), AtLoc(at), RParenLoc(rp){}
|
||||
explicit ObjCSelectorExpr(EmptyShell Empty)
|
||||
: Expr(ObjCSelectorExprClass, Empty) {}
|
||||
|
||||
@ -117,7 +119,7 @@ class ObjCSelectorExpr : public Expr {
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
@ -130,8 +132,7 @@ class ObjCSelectorExpr : public Expr {
|
||||
static bool classof(const ObjCSelectorExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// ObjCProtocolExpr used for protocol expression in Objective-C. This is used
|
||||
@ -144,8 +145,9 @@ class ObjCProtocolExpr : public Expr {
|
||||
public:
|
||||
ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCProtocolExprClass, T, false, false), TheProtocol(protocol),
|
||||
AtLoc(at), RParenLoc(rp) {}
|
||||
: Expr(ObjCProtocolExprClass, T, VK_RValue, OK_Ordinary, false, false,
|
||||
false),
|
||||
TheProtocol(protocol), AtLoc(at), RParenLoc(rp) {}
|
||||
explicit ObjCProtocolExpr(EmptyShell Empty)
|
||||
: Expr(ObjCProtocolExprClass, Empty) {}
|
||||
|
||||
@ -157,7 +159,7 @@ class ObjCProtocolExpr : public Expr {
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
@ -167,8 +169,7 @@ class ObjCProtocolExpr : public Expr {
|
||||
static bool classof(const ObjCProtocolExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// ObjCIvarRefExpr - A reference to an ObjC instance variable.
|
||||
@ -180,13 +181,13 @@ class ObjCIvarRefExpr : public Expr {
|
||||
bool IsFreeIvar:1; // True if ivar reference has no base (self assumed).
|
||||
|
||||
public:
|
||||
ObjCIvarRefExpr(ObjCIvarDecl *d,
|
||||
QualType t, SourceLocation l, Expr *base,
|
||||
ObjCIvarRefExpr(ObjCIvarDecl *d, QualType t,
|
||||
SourceLocation l, Expr *base,
|
||||
bool arrow = false, bool freeIvar = false) :
|
||||
Expr(ObjCIvarRefExprClass, t, /*TypeDependent=*/false,
|
||||
base->isValueDependent()), D(d),
|
||||
Loc(l), Base(base), IsArrow(arrow),
|
||||
IsFreeIvar(freeIvar) {}
|
||||
Expr(ObjCIvarRefExprClass, t, VK_LValue, OK_Ordinary,
|
||||
/*TypeDependent=*/false, base->isValueDependent(),
|
||||
base->containsUnexpandedParameterPack()),
|
||||
D(d), Loc(l), Base(base), IsArrow(arrow), IsFreeIvar(freeIvar) {}
|
||||
|
||||
explicit ObjCIvarRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCIvarRefExprClass, Empty) {}
|
||||
@ -207,7 +208,7 @@ class ObjCIvarRefExpr : public Expr {
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return isFreeIvar() ? SourceRange(Loc)
|
||||
: SourceRange(getBase()->getLocStart(), Loc);
|
||||
}
|
||||
@ -218,8 +219,7 @@ class ObjCIvarRefExpr : public Expr {
|
||||
static bool classof(const ObjCIvarRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(&Base, &Base+1); }
|
||||
};
|
||||
|
||||
/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
|
||||
@ -227,32 +227,127 @@ class ObjCIvarRefExpr : public Expr {
|
||||
///
|
||||
class ObjCPropertyRefExpr : public Expr {
|
||||
private:
|
||||
ObjCPropertyDecl *AsProperty;
|
||||
/// If the bool is true, this is an implicit property reference; the
|
||||
/// pointer is an (optional) ObjCMethodDecl and Setter may be set.
|
||||
/// if the bool is false, this is an explicit property reference;
|
||||
/// the pointer is an ObjCPropertyDecl and Setter is always null.
|
||||
llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter;
|
||||
ObjCMethodDecl *Setter;
|
||||
|
||||
SourceLocation IdLoc;
|
||||
Stmt *Base;
|
||||
|
||||
/// \brief When the receiver in property access is 'super', this is
|
||||
/// the location of the 'super' keyword. When it's an interface,
|
||||
/// this is that interface.
|
||||
SourceLocation ReceiverLoc;
|
||||
llvm::PointerUnion3<Stmt*, const Type*, ObjCInterfaceDecl*> Receiver;
|
||||
|
||||
public:
|
||||
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCPropertyRefExprClass, t, /*TypeDependent=*/false,
|
||||
base->isValueDependent()),
|
||||
AsProperty(PD), IdLoc(l), Base(base) {
|
||||
: Expr(ObjCPropertyRefExprClass, t, VK, OK,
|
||||
/*TypeDependent=*/false, base->isValueDependent(),
|
||||
base->containsUnexpandedParameterPack()),
|
||||
PropertyOrGetter(PD, false), Setter(0),
|
||||
IdLoc(l), ReceiverLoc(), Receiver(base) {
|
||||
}
|
||||
|
||||
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation l, SourceLocation sl, QualType st)
|
||||
: Expr(ObjCPropertyRefExprClass, t, VK, OK,
|
||||
/*TypeDependent=*/false, false,
|
||||
st->containsUnexpandedParameterPack()),
|
||||
PropertyOrGetter(PD, false), Setter(0),
|
||||
IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) {
|
||||
}
|
||||
|
||||
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
|
||||
QualType T, ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation IdLoc, Expr *Base)
|
||||
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false,
|
||||
Base->isValueDependent(),
|
||||
Base->containsUnexpandedParameterPack()),
|
||||
PropertyOrGetter(Getter, true), Setter(Setter),
|
||||
IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) {
|
||||
}
|
||||
|
||||
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
|
||||
QualType T, ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation IdLoc,
|
||||
SourceLocation SuperLoc, QualType SuperTy)
|
||||
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false),
|
||||
PropertyOrGetter(Getter, true), Setter(Setter),
|
||||
IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) {
|
||||
}
|
||||
|
||||
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
|
||||
QualType T, ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation IdLoc,
|
||||
SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver)
|
||||
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false),
|
||||
PropertyOrGetter(Getter, true), Setter(Setter),
|
||||
IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) {
|
||||
}
|
||||
|
||||
explicit ObjCPropertyRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCPropertyRefExprClass, Empty) {}
|
||||
|
||||
ObjCPropertyDecl *getProperty() const { return AsProperty; }
|
||||
void setProperty(ObjCPropertyDecl *D) { AsProperty = D; }
|
||||
bool isImplicitProperty() const { return PropertyOrGetter.getInt(); }
|
||||
bool isExplicitProperty() const { return !PropertyOrGetter.getInt(); }
|
||||
|
||||
const Expr *getBase() const { return cast<Expr>(Base); }
|
||||
Expr *getBase() { return cast<Expr>(Base); }
|
||||
void setBase(Expr *base) { Base = base; }
|
||||
ObjCPropertyDecl *getExplicitProperty() const {
|
||||
assert(!isImplicitProperty());
|
||||
return cast<ObjCPropertyDecl>(PropertyOrGetter.getPointer());
|
||||
}
|
||||
|
||||
ObjCMethodDecl *getImplicitPropertyGetter() const {
|
||||
assert(isImplicitProperty());
|
||||
return cast_or_null<ObjCMethodDecl>(PropertyOrGetter.getPointer());
|
||||
}
|
||||
|
||||
ObjCMethodDecl *getImplicitPropertySetter() const {
|
||||
assert(isImplicitProperty());
|
||||
return Setter;
|
||||
}
|
||||
|
||||
Selector getGetterSelector() const {
|
||||
if (isImplicitProperty())
|
||||
return getImplicitPropertyGetter()->getSelector();
|
||||
return getExplicitProperty()->getGetterName();
|
||||
}
|
||||
|
||||
Selector getSetterSelector() const {
|
||||
if (isImplicitProperty())
|
||||
return getImplicitPropertySetter()->getSelector();
|
||||
return getExplicitProperty()->getSetterName();
|
||||
}
|
||||
|
||||
const Expr *getBase() const {
|
||||
return cast<Expr>(Receiver.get<Stmt*>());
|
||||
}
|
||||
Expr *getBase() {
|
||||
return cast<Expr>(Receiver.get<Stmt*>());
|
||||
}
|
||||
|
||||
SourceLocation getLocation() const { return IdLoc; }
|
||||
void setLocation(SourceLocation L) { IdLoc = L; }
|
||||
|
||||
SourceLocation getReceiverLocation() const { return ReceiverLoc; }
|
||||
QualType getSuperReceiverType() const {
|
||||
return QualType(Receiver.get<const Type*>(), 0);
|
||||
}
|
||||
ObjCInterfaceDecl *getClassReceiver() const {
|
||||
return Receiver.get<ObjCInterfaceDecl*>();
|
||||
}
|
||||
bool isObjectReceiver() const { return Receiver.is<Stmt*>(); }
|
||||
bool isSuperReceiver() const { return Receiver.is<const Type*>(); }
|
||||
bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), IdLoc);
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange((isObjectReceiver() ? getBase()->getLocStart()
|
||||
: getReceiverLocation()),
|
||||
IdLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
@ -261,89 +356,32 @@ class ObjCPropertyRefExpr : public Expr {
|
||||
static bool classof(const ObjCPropertyRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCImplicitSetterGetterRefExpr - A dot-syntax expression to access two
|
||||
/// methods; one to set a value to an 'ivar' (Setter) and the other to access
|
||||
/// an 'ivar' (Setter).
|
||||
/// An example for use of this AST is:
|
||||
/// @code
|
||||
/// @interface Test { }
|
||||
/// - (Test *)crash;
|
||||
/// - (void)setCrash: (Test*)value;
|
||||
/// @end
|
||||
/// void foo(Test *p1, Test *p2)
|
||||
/// {
|
||||
/// p2.crash = p1.crash; // Uses ObjCImplicitSetterGetterRefExpr AST
|
||||
/// }
|
||||
/// @endcode
|
||||
class ObjCImplicitSetterGetterRefExpr : public Expr {
|
||||
/// Setter - Setter method user declared for setting its 'ivar' to a value
|
||||
ObjCMethodDecl *Setter;
|
||||
/// Getter - Getter method user declared for accessing 'ivar' it controls.
|
||||
ObjCMethodDecl *Getter;
|
||||
/// Location of the member in the dot syntax notation. This is location
|
||||
/// of the getter method.
|
||||
SourceLocation MemberLoc;
|
||||
// FIXME: Swizzle these into a single pointer.
|
||||
Stmt *Base;
|
||||
ObjCInterfaceDecl *InterfaceDecl;
|
||||
/// Location of the receiver class in the dot syntax notation
|
||||
/// used to call a class method setter/getter.
|
||||
SourceLocation ClassLoc;
|
||||
|
||||
public:
|
||||
ObjCImplicitSetterGetterRefExpr(ObjCMethodDecl *getter,
|
||||
QualType t,
|
||||
ObjCMethodDecl *setter,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCImplicitSetterGetterRefExprClass, t, /*TypeDependent=*/false,
|
||||
base->isValueDependent()),
|
||||
Setter(setter), Getter(getter), MemberLoc(l), Base(base),
|
||||
InterfaceDecl(0), ClassLoc(SourceLocation()) {
|
||||
child_range children() {
|
||||
if (Receiver.is<Stmt*>()) {
|
||||
Stmt **begin = reinterpret_cast<Stmt**>(&Receiver); // hack!
|
||||
return child_range(begin, begin+1);
|
||||
}
|
||||
ObjCImplicitSetterGetterRefExpr(ObjCMethodDecl *getter,
|
||||
QualType t,
|
||||
ObjCMethodDecl *setter,
|
||||
SourceLocation l, ObjCInterfaceDecl *C, SourceLocation CL)
|
||||
: Expr(ObjCImplicitSetterGetterRefExprClass, t, false, false),
|
||||
Setter(setter), Getter(getter), MemberLoc(l), Base(0), InterfaceDecl(C),
|
||||
ClassLoc(CL) {
|
||||
}
|
||||
explicit ObjCImplicitSetterGetterRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCImplicitSetterGetterRefExprClass, Empty){}
|
||||
|
||||
ObjCMethodDecl *getGetterMethod() const { return Getter; }
|
||||
ObjCMethodDecl *getSetterMethod() const { return Setter; }
|
||||
ObjCInterfaceDecl *getInterfaceDecl() const { return InterfaceDecl; }
|
||||
void setGetterMethod(ObjCMethodDecl *D) { Getter = D; }
|
||||
void setSetterMethod(ObjCMethodDecl *D) { Setter = D; }
|
||||
void setInterfaceDecl(ObjCInterfaceDecl *D) { InterfaceDecl = D; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
if (Base)
|
||||
return SourceRange(getBase()->getLocStart(), MemberLoc);
|
||||
return SourceRange(ClassLoc, MemberLoc);
|
||||
return child_range();
|
||||
}
|
||||
const Expr *getBase() const { return cast_or_null<Expr>(Base); }
|
||||
Expr *getBase() { return cast_or_null<Expr>(Base); }
|
||||
void setBase(Expr *base) { Base = base; }
|
||||
|
||||
SourceLocation getLocation() const { return MemberLoc; }
|
||||
void setLocation(SourceLocation L) { MemberLoc = L; }
|
||||
SourceLocation getClassLoc() const { return ClassLoc; }
|
||||
void setClassLoc(SourceLocation L) { ClassLoc = L; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCImplicitSetterGetterRefExprClass;
|
||||
private:
|
||||
friend class ASTStmtReader;
|
||||
void setExplicitProperty(ObjCPropertyDecl *D) {
|
||||
PropertyOrGetter.setPointer(D);
|
||||
PropertyOrGetter.setInt(false);
|
||||
Setter = 0;
|
||||
}
|
||||
static bool classof(const ObjCImplicitSetterGetterRefExpr *) { return true; }
|
||||
void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter) {
|
||||
PropertyOrGetter.setPointer(Getter);
|
||||
PropertyOrGetter.setInt(true);
|
||||
this->Setter = Setter;
|
||||
}
|
||||
void setBase(Expr *Base) { Receiver = Base; }
|
||||
void setSuperReceiver(QualType T) { Receiver = T.getTypePtr(); }
|
||||
void setClassReceiver(ObjCInterfaceDecl *D) { Receiver = D; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
void setLocation(SourceLocation L) { IdLoc = L; }
|
||||
void setReceiverLocation(SourceLocation Loc) { ReceiverLoc = Loc; }
|
||||
};
|
||||
|
||||
/// \brief An expression that sends a message to the given Objective-C
|
||||
@ -396,6 +434,9 @@ class ObjCMessageExpr : public Expr {
|
||||
/// referring to the method that we type-checked against.
|
||||
uintptr_t SelectorOrMethod;
|
||||
|
||||
/// \brief Location of the selector.
|
||||
SourceLocation SelectorLoc;
|
||||
|
||||
/// \brief The source locations of the open and close square
|
||||
/// brackets ('[' and ']', respectively).
|
||||
SourceLocation LBracLoc, RBracLoc;
|
||||
@ -404,26 +445,29 @@ class ObjCMessageExpr : public Expr {
|
||||
: Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0),
|
||||
HasMethod(0), SelectorOrMethod(0) { }
|
||||
|
||||
ObjCMessageExpr(QualType T,
|
||||
ObjCMessageExpr(QualType T, ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
SourceLocation SuperLoc,
|
||||
bool IsInstanceSuper,
|
||||
QualType SuperType,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RBracLoc);
|
||||
ObjCMessageExpr(QualType T,
|
||||
ObjCMessageExpr(QualType T, ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
TypeSourceInfo *Receiver,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RBracLoc);
|
||||
ObjCMessageExpr(QualType T,
|
||||
ObjCMessageExpr(QualType T, ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
Expr *Receiver,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RBracLoc);
|
||||
@ -458,6 +502,10 @@ class ObjCMessageExpr : public Expr {
|
||||
///
|
||||
/// \param T The result type of this message.
|
||||
///
|
||||
/// \param VK The value kind of this message. A message returning
|
||||
/// a l-value or r-value reference will be an l-value or x-value,
|
||||
/// respectively.
|
||||
///
|
||||
/// \param LBrac The location of the open square bracket '['.
|
||||
///
|
||||
/// \param SuperLoc The location of the "super" keyword.
|
||||
@ -475,12 +523,14 @@ class ObjCMessageExpr : public Expr {
|
||||
/// \param NumArgs The number of arguments.
|
||||
///
|
||||
/// \param RBracLoc The location of the closing square bracket ']'.
|
||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
||||
ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
SourceLocation SuperLoc,
|
||||
bool IsInstanceSuper,
|
||||
QualType SuperType,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RBracLoc);
|
||||
@ -491,6 +541,10 @@ class ObjCMessageExpr : public Expr {
|
||||
///
|
||||
/// \param T The result type of this message.
|
||||
///
|
||||
/// \param VK The value kind of this message. A message returning
|
||||
/// a l-value or r-value reference will be an l-value or x-value,
|
||||
/// respectively.
|
||||
///
|
||||
/// \param LBrac The location of the open square bracket '['.
|
||||
///
|
||||
/// \param Receiver The type of the receiver, including
|
||||
@ -507,9 +561,11 @@ class ObjCMessageExpr : public Expr {
|
||||
///
|
||||
/// \param RBracLoc The location of the closing square bracket ']'.
|
||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
||||
ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
TypeSourceInfo *Receiver,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RBracLoc);
|
||||
@ -520,6 +576,10 @@ class ObjCMessageExpr : public Expr {
|
||||
///
|
||||
/// \param T The result type of this message.
|
||||
///
|
||||
/// \param VK The value kind of this message. A message returning
|
||||
/// a l-value or r-value reference will be an l-value or x-value,
|
||||
/// respectively.
|
||||
///
|
||||
/// \param LBrac The location of the open square bracket '['.
|
||||
///
|
||||
/// \param Receiver The expression used to produce the object that
|
||||
@ -536,9 +596,11 @@ class ObjCMessageExpr : public Expr {
|
||||
///
|
||||
/// \param RBracLoc The location of the closing square bracket ']'.
|
||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
||||
ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
Expr *Receiver,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RBracLoc);
|
||||
@ -556,6 +618,9 @@ class ObjCMessageExpr : public Expr {
|
||||
/// sent to.
|
||||
ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; }
|
||||
|
||||
/// \brief Source range of the receiver.
|
||||
SourceRange getReceiverRange() const;
|
||||
|
||||
/// \brief Determine whether this is an instance message to either a
|
||||
/// computed object or to super.
|
||||
bool isInstanceMessage() const {
|
||||
@ -682,11 +747,11 @@ class ObjCMessageExpr : public Expr {
|
||||
|
||||
/// \brief Retrieve the arguments to this message, not including the
|
||||
/// receiver.
|
||||
Stmt **getArgs() {
|
||||
return reinterpret_cast<Stmt **>(this + 1) + 1;
|
||||
Expr **getArgs() {
|
||||
return reinterpret_cast<Expr **>(this + 1) + 1;
|
||||
}
|
||||
const Stmt * const *getArgs() const {
|
||||
return reinterpret_cast<const Stmt * const *>(this + 1) + 1;
|
||||
const Expr * const *getArgs() const {
|
||||
return reinterpret_cast<const Expr * const *>(this + 1) + 1;
|
||||
}
|
||||
|
||||
/// getArg - Return the specified argument.
|
||||
@ -706,15 +771,13 @@ class ObjCMessageExpr : public Expr {
|
||||
|
||||
SourceLocation getLeftLoc() const { return LBracLoc; }
|
||||
SourceLocation getRightLoc() const { return RBracLoc; }
|
||||
|
||||
void setLeftLoc(SourceLocation L) { LBracLoc = L; }
|
||||
void setRightLoc(SourceLocation L) { RBracLoc = L; }
|
||||
SourceLocation getSelectorLoc() const { return SelectorLoc; }
|
||||
|
||||
void setSourceRange(SourceRange R) {
|
||||
LBracLoc = R.getBegin();
|
||||
RBracLoc = R.getEnd();
|
||||
}
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(LBracLoc, RBracLoc);
|
||||
}
|
||||
|
||||
@ -724,43 +787,24 @@ class ObjCMessageExpr : public Expr {
|
||||
static bool classof(const ObjCMessageExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children();
|
||||
|
||||
typedef ExprIterator arg_iterator;
|
||||
typedef ConstExprIterator const_arg_iterator;
|
||||
|
||||
arg_iterator arg_begin() { return getArgs(); }
|
||||
arg_iterator arg_end() { return getArgs() + NumArgs; }
|
||||
const_arg_iterator arg_begin() const { return getArgs(); }
|
||||
const_arg_iterator arg_end() const { return getArgs() + NumArgs; }
|
||||
};
|
||||
|
||||
/// ObjCSuperExpr - Represents the "super" expression in Objective-C,
|
||||
/// which refers to the object on which the current method is executing.
|
||||
///
|
||||
/// FIXME: This class is intended for removal, once its remaining
|
||||
/// clients have been altered to represent "super" internally.
|
||||
class ObjCSuperExpr : public Expr {
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
ObjCSuperExpr(SourceLocation L, QualType Type)
|
||||
: Expr(ObjCSuperExprClass, Type, false, false), Loc(L) { }
|
||||
explicit ObjCSuperExpr(EmptyShell Empty) : Expr(ObjCSuperExprClass, Empty) {}
|
||||
|
||||
SourceLocation getLoc() const { return Loc; }
|
||||
void setLoc(SourceLocation L) { Loc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCSuperExprClass;
|
||||
arg_iterator arg_begin() { return reinterpret_cast<Stmt **>(getArgs()); }
|
||||
arg_iterator arg_end() {
|
||||
return reinterpret_cast<Stmt **>(getArgs() + NumArgs);
|
||||
}
|
||||
const_arg_iterator arg_begin() const {
|
||||
return reinterpret_cast<Stmt const * const*>(getArgs());
|
||||
}
|
||||
const_arg_iterator arg_end() const {
|
||||
return reinterpret_cast<Stmt const * const*>(getArgs() + NumArgs);
|
||||
}
|
||||
static bool classof(const ObjCSuperExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
};
|
||||
|
||||
/// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type.
|
||||
@ -776,8 +820,9 @@ class ObjCIsaExpr : public Expr {
|
||||
bool IsArrow;
|
||||
public:
|
||||
ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty)
|
||||
: Expr(ObjCIsaExprClass, ty, /*TypeDependent=*/false,
|
||||
base->isValueDependent()),
|
||||
: Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary,
|
||||
/*TypeDependent=*/false, base->isValueDependent(),
|
||||
/*ContainsUnexpandedParameterPack=*/false),
|
||||
Base(base), IsaMemberLoc(l), IsArrow(isarrow) {}
|
||||
|
||||
/// \brief Build an empty expression.
|
||||
@ -794,11 +839,11 @@ class ObjCIsaExpr : public Expr {
|
||||
SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; }
|
||||
void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), IsaMemberLoc);
|
||||
}
|
||||
|
||||
virtual SourceLocation getExprLoc() const { return IsaMemberLoc; }
|
||||
SourceLocation getExprLoc() const { return IsaMemberLoc; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCIsaExprClass;
|
||||
@ -806,8 +851,7 @@ class ObjCIsaExpr : public Expr {
|
||||
static bool classof(const ObjCIsaExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(&Base, &Base+1); }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -14,6 +14,7 @@
|
||||
#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
||||
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
@ -24,6 +25,7 @@ template <class T> class SmallVectorImpl;
|
||||
namespace clang {
|
||||
|
||||
class ASTConsumer;
|
||||
class CXXBaseSpecifier;
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class DeclContextLookupResult;
|
||||
@ -32,6 +34,7 @@ class ExternalSemaSource; // layering violation required for downcasting
|
||||
class NamedDecl;
|
||||
class Selector;
|
||||
class Stmt;
|
||||
class TagDecl;
|
||||
|
||||
/// \brief Abstract interface for external sources of AST nodes.
|
||||
///
|
||||
@ -91,6 +94,10 @@ class ExternalASTSource {
|
||||
/// FunctionDecl::setLazyBody when building decls.
|
||||
virtual Stmt *GetExternalDeclStmt(uint64_t Offset) = 0;
|
||||
|
||||
/// \brief Resolve the offset of a set of C++ base specifiers in the decl
|
||||
/// stream into an array of specifiers.
|
||||
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) = 0;
|
||||
|
||||
/// \brief Finds all declarations with the given name in the
|
||||
/// given context.
|
||||
///
|
||||
@ -110,12 +117,44 @@ class ExternalASTSource {
|
||||
virtual void MaterializeVisibleDecls(const DeclContext *DC) = 0;
|
||||
|
||||
/// \brief Finds all declarations lexically contained within the given
|
||||
/// DeclContext.
|
||||
/// DeclContext, after applying an optional filter predicate.
|
||||
///
|
||||
/// \param isKindWeWant a predicate function that returns true if the passed
|
||||
/// declaration kind is one we are looking for. If NULL, all declarations
|
||||
/// are returned.
|
||||
///
|
||||
/// \return true if an error occurred
|
||||
virtual bool FindExternalLexicalDecls(const DeclContext *DC,
|
||||
llvm::SmallVectorImpl<Decl*> &Result) = 0;
|
||||
bool (*isKindWeWant)(Decl::Kind),
|
||||
llvm::SmallVectorImpl<Decl*> &Result) = 0;
|
||||
|
||||
/// \brief Finds all declarations lexically contained within the given
|
||||
/// DeclContext.
|
||||
///
|
||||
/// \return true if an error occurred
|
||||
bool FindExternalLexicalDecls(const DeclContext *DC,
|
||||
llvm::SmallVectorImpl<Decl*> &Result) {
|
||||
return FindExternalLexicalDecls(DC, 0, Result);
|
||||
}
|
||||
|
||||
template <typename DeclTy>
|
||||
bool FindExternalLexicalDeclsBy(const DeclContext *DC,
|
||||
llvm::SmallVectorImpl<Decl*> &Result) {
|
||||
return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
|
||||
}
|
||||
|
||||
/// \brief Gives the external AST source an opportunity to complete
|
||||
/// an incomplete type.
|
||||
virtual void CompleteType(TagDecl *Tag) {}
|
||||
|
||||
/// \brief Gives the external AST source an opportunity to complete an
|
||||
/// incomplete Objective-C class.
|
||||
///
|
||||
/// This routine will only be invoked if the "externally completed" bit is
|
||||
/// set on the ObjCInterfaceDecl via the function
|
||||
/// \c ObjCInterfaceDecl::setExternallyCompleted().
|
||||
virtual void CompleteType(ObjCInterfaceDecl *Class) { }
|
||||
|
||||
/// \brief Notify ExternalASTSource that we started deserialization of
|
||||
/// a decl or type so until FinishedDeserializing is called there may be
|
||||
/// decls that are initializing. Must be paired with FinishedDeserializing.
|
||||
@ -227,6 +266,11 @@ typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>
|
||||
typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>
|
||||
LazyDeclPtr;
|
||||
|
||||
/// \brief A lazy pointer to a set of CXXBaseSpecifiers.
|
||||
typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
|
||||
&ExternalASTSource::GetExternalCXXBaseSpecifiers>
|
||||
LazyCXXBaseSpecifiersPtr;
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
||||
|
@ -1,88 +0,0 @@
|
||||
//===--- FullExpr.h - C++ full expression class -----------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the FullExpr interface, to be used for type safe handling
|
||||
// of full expressions.
|
||||
//
|
||||
// Full expressions are described in C++ [intro.execution]p12.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_FULLEXPR_H
|
||||
#define LLVM_CLANG_AST_FULLEXPR_H
|
||||
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class CXXTemporary;
|
||||
class Expr;
|
||||
|
||||
class FullExpr {
|
||||
struct ExprAndTemporaries {
|
||||
Expr *SubExpr;
|
||||
|
||||
unsigned NumTemps;
|
||||
|
||||
typedef CXXTemporary** temps_iterator;
|
||||
|
||||
temps_iterator temps_begin() {
|
||||
return reinterpret_cast<CXXTemporary **>(this + 1);
|
||||
}
|
||||
temps_iterator temps_end() {
|
||||
return temps_begin() + NumTemps;
|
||||
}
|
||||
};
|
||||
|
||||
typedef llvm::PointerUnion<Expr *, ExprAndTemporaries *> SubExprTy;
|
||||
SubExprTy SubExpr;
|
||||
|
||||
FullExpr() { }
|
||||
|
||||
public:
|
||||
static FullExpr Create(ASTContext &Context, Expr *SubExpr,
|
||||
CXXTemporary **Temps, unsigned NumTemps);
|
||||
|
||||
Expr *getExpr() {
|
||||
if (Expr *E = SubExpr.dyn_cast<Expr *>())
|
||||
return E;
|
||||
|
||||
return SubExpr.get<ExprAndTemporaries *>()->SubExpr;
|
||||
}
|
||||
|
||||
const Expr *getExpr() const {
|
||||
return const_cast<FullExpr*>(this)->getExpr();
|
||||
}
|
||||
|
||||
typedef CXXTemporary** temps_iterator;
|
||||
|
||||
temps_iterator temps_begin() {
|
||||
if (ExprAndTemporaries *ET = SubExpr.dyn_cast<ExprAndTemporaries *>())
|
||||
return ET->temps_begin();
|
||||
|
||||
return 0;
|
||||
}
|
||||
temps_iterator temps_end() {
|
||||
if (ExprAndTemporaries *ET = SubExpr.dyn_cast<ExprAndTemporaries *>())
|
||||
return ET->temps_end();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *getAsOpaquePtr() const { return SubExpr.getOpaqueValue(); }
|
||||
|
||||
static FullExpr getFromOpaquePtr(void *Ptr) {
|
||||
FullExpr E;
|
||||
E.SubExpr = SubExprTy::getFromOpaqueValue(Ptr);
|
||||
return E;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -7,20 +7,15 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements C++ name mangling according to the Itanium C++ ABI,
|
||||
// which is used in GCC 3.2 and newer (and many compilers that are
|
||||
// ABI-compatible with GCC):
|
||||
//
|
||||
// http://www.codesourcery.com/public/cxx-abi/abi.html
|
||||
// Defines the C++ name mangling interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_CODEGEN_MANGLE_H
|
||||
#define LLVM_CLANG_CODEGEN_MANGLE_H
|
||||
#ifndef LLVM_CLANG_AST_MANGLE_H
|
||||
#define LLVM_CLANG_AST_MANGLE_H
|
||||
|
||||
#include "CGCXX.h"
|
||||
#include "GlobalDecl.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/ABI.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
@ -36,8 +31,6 @@ namespace clang {
|
||||
class NamedDecl;
|
||||
class ObjCMethodDecl;
|
||||
class VarDecl;
|
||||
|
||||
namespace CodeGen {
|
||||
struct ThisAdjustment;
|
||||
struct ThunkInfo;
|
||||
|
||||
@ -74,9 +67,6 @@ class MangleContext {
|
||||
ASTContext &Context;
|
||||
Diagnostic &Diags;
|
||||
|
||||
llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
|
||||
unsigned Discriminator;
|
||||
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
|
||||
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
|
||||
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
|
||||
|
||||
@ -91,15 +81,8 @@ class MangleContext {
|
||||
|
||||
Diagnostic &getDiags() const { return Diags; }
|
||||
|
||||
void startNewFunction() { LocalBlockIds.clear(); }
|
||||
virtual void startNewFunction() { LocalBlockIds.clear(); }
|
||||
|
||||
uint64_t getAnonymousStructId(const TagDecl *TD) {
|
||||
std::pair<llvm::DenseMap<const TagDecl *,
|
||||
uint64_t>::iterator, bool> Result =
|
||||
AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size()));
|
||||
return Result.first->second;
|
||||
}
|
||||
|
||||
unsigned getBlockId(const BlockDecl *BD, bool Local) {
|
||||
llvm::DenseMap<const BlockDecl *, unsigned> &BlockIds
|
||||
= Local? LocalBlockIds : GlobalBlockIds;
|
||||
@ -111,67 +94,57 @@ class MangleContext {
|
||||
/// @name Mangler Entry Points
|
||||
/// @{
|
||||
|
||||
virtual bool shouldMangleDeclName(const NamedDecl *D);
|
||||
virtual void mangleName(const NamedDecl *D, llvm::SmallVectorImpl<char> &);
|
||||
virtual bool shouldMangleDeclName(const NamedDecl *D) = 0;
|
||||
virtual void mangleName(const NamedDecl *D, llvm::raw_ostream &)=0;
|
||||
virtual void mangleThunk(const CXXMethodDecl *MD,
|
||||
const ThunkInfo &Thunk,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
|
||||
const ThisAdjustment &ThisAdjustment,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
virtual void mangleGuardVariable(const VarDecl *D,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
llvm::raw_ostream &) = 0;
|
||||
virtual void mangleReferenceTemporary(const VarDecl *D,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
|
||||
const CXXRecordDecl *Type,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
virtual void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &);
|
||||
virtual void mangleCXXRTTIName(QualType T, llvm::SmallVectorImpl<char> &);
|
||||
llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTI(QualType T, llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTIName(QualType T, llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
void mangleBlock(GlobalDecl GD,
|
||||
const BlockDecl *BD, llvm::SmallVectorImpl<char> &);
|
||||
llvm::raw_ostream &) = 0;
|
||||
|
||||
void mangleInitDiscriminator() {
|
||||
Discriminator = 0;
|
||||
}
|
||||
void mangleGlobalBlock(const BlockDecl *BD,
|
||||
llvm::raw_ostream &Out);
|
||||
void mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT,
|
||||
const BlockDecl *BD, llvm::raw_ostream &Out);
|
||||
void mangleDtorBlock(const CXXDestructorDecl *CD, CXXDtorType DT,
|
||||
const BlockDecl *BD, llvm::raw_ostream &Out);
|
||||
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
|
||||
llvm::raw_ostream &Out);
|
||||
// Do the right thing.
|
||||
void mangleBlock(const BlockDecl *BD, llvm::raw_ostream &Out);
|
||||
|
||||
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
|
||||
unsigned &discriminator = Uniquifier[ND];
|
||||
if (!discriminator)
|
||||
discriminator = ++Discriminator;
|
||||
if (discriminator == 1)
|
||||
return false;
|
||||
disc = discriminator-2;
|
||||
return true;
|
||||
void mangleObjCMethodName(const ObjCMethodDecl *MD,
|
||||
llvm::raw_ostream &);
|
||||
|
||||
// This is pretty lame.
|
||||
virtual void mangleItaniumGuardVariable(const VarDecl *D,
|
||||
llvm::raw_ostream &) {
|
||||
assert(0 && "Target does not support mangling guard variables");
|
||||
}
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// MiscNameMangler - Mangles Objective-C method names and blocks.
|
||||
class MiscNameMangler {
|
||||
MangleContext &Context;
|
||||
llvm::raw_svector_ostream Out;
|
||||
|
||||
ASTContext &getASTContext() const { return Context.getASTContext(); }
|
||||
MangleContext *createItaniumMangleContext(ASTContext &Context,
|
||||
Diagnostic &Diags);
|
||||
MangleContext *createMicrosoftMangleContext(ASTContext &Context,
|
||||
Diagnostic &Diags);
|
||||
|
||||
public:
|
||||
MiscNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res);
|
||||
|
||||
llvm::raw_svector_ostream &getStream() { return Out; }
|
||||
|
||||
void mangleBlock(GlobalDecl GD, const BlockDecl *BD);
|
||||
void mangleObjCMethodName(const ObjCMethodDecl *MD);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -90,7 +90,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
|
||||
/// \brief Either find or insert the given nested name specifier
|
||||
/// mockup in the given context.
|
||||
static NestedNameSpecifier *FindOrInsert(ASTContext &Context,
|
||||
static NestedNameSpecifier *FindOrInsert(const ASTContext &Context,
|
||||
const NestedNameSpecifier &Mockup);
|
||||
|
||||
public:
|
||||
@ -99,19 +99,19 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
/// The prefix must be dependent, since nested name specifiers
|
||||
/// referencing an identifier are only permitted when the identifier
|
||||
/// cannot be resolved.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
IdentifierInfo *II);
|
||||
|
||||
/// \brief Builds a nested name specifier that names a namespace.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
NamespaceDecl *NS);
|
||||
|
||||
/// \brief Builds a nested name specifier that names a type.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
bool Template, Type *T);
|
||||
bool Template, const Type *T);
|
||||
|
||||
/// \brief Builds a specifier that consists of just an identifier.
|
||||
///
|
||||
@ -119,11 +119,12 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
/// prefix because the prefix is implied by something outside of the
|
||||
/// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent
|
||||
/// type.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context, IdentifierInfo *II);
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
IdentifierInfo *II);
|
||||
|
||||
/// \brief Returns the nested name specifier representing the global
|
||||
/// scope.
|
||||
static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context);
|
||||
static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context);
|
||||
|
||||
/// \brief Return the prefix of this nested name specifier.
|
||||
///
|
||||
@ -160,10 +161,10 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type stored in this nested name specifier.
|
||||
Type *getAsType() const {
|
||||
const Type *getAsType() const {
|
||||
if (Prefix.getInt() == TypeSpec ||
|
||||
Prefix.getInt() == TypeSpecWithTemplate)
|
||||
return (Type *)Specifier;
|
||||
return (const Type *)Specifier;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -172,6 +173,10 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
/// type or not.
|
||||
bool isDependent() const;
|
||||
|
||||
/// \brief Whether this nested-name-specifier contains an unexpanded
|
||||
/// parameter pack (for C++0x variadic templates).
|
||||
bool containsUnexpandedParameterPack() const;
|
||||
|
||||
/// \brief Print this nested name specifier to the given output
|
||||
/// stream.
|
||||
void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
|
||||
|
@ -17,107 +17,238 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// CastKind - the kind of cast this represents.
|
||||
/// CastKind - The kind of operation required for a conversion.
|
||||
enum CastKind {
|
||||
/// CK_Unknown - Unknown cast kind.
|
||||
/// FIXME: The goal is to get rid of this and make all casts have a
|
||||
/// kind so that the AST client doesn't have to try to figure out what's
|
||||
/// going on.
|
||||
CK_Unknown,
|
||||
/// CK_Dependent - A conversion which cannot yet be analyzed because
|
||||
/// either the expression or target type is dependent. These are
|
||||
/// created only for explicit casts; dependent ASTs aren't required
|
||||
/// to even approximately type-check.
|
||||
/// (T*) malloc(sizeof(T))
|
||||
/// reinterpret_cast<intptr_t>(A<T>::alloc());
|
||||
CK_Dependent,
|
||||
|
||||
/// CK_BitCast - Used for reinterpret_cast.
|
||||
/// CK_BitCast - A conversion which causes a bit pattern of one type
|
||||
/// to be reinterpreted as a bit pattern of another type. Generally
|
||||
/// the operands must have equivalent size and unrelated types.
|
||||
///
|
||||
/// The pointer conversion char* -> int* is a bitcast. Many other
|
||||
/// pointer conversions which are "physically" bitcasts are given
|
||||
/// special cast kinds.
|
||||
///
|
||||
/// Vector coercions are bitcasts.
|
||||
CK_BitCast,
|
||||
|
||||
/// CK_LValueBitCast - Used for reinterpret_cast of expressions to
|
||||
/// a reference type.
|
||||
/// CK_LValueBitCast - A conversion which reinterprets the address of
|
||||
/// an l-value as an l-value of a different kind. Used for
|
||||
/// reinterpret_casts of l-value expressions to reference types.
|
||||
/// bool b; reinterpret_cast<char&>(b) = 'a';
|
||||
CK_LValueBitCast,
|
||||
|
||||
/// CK_LValueToRValue - A conversion which causes the extraction of
|
||||
/// an r-value from the operand gl-value. The result of an r-value
|
||||
/// conversion is always unqualified.
|
||||
CK_LValueToRValue,
|
||||
|
||||
/// CK_GetObjCProperty - A conversion which calls an Objective-C
|
||||
/// property getter. The operand is an OK_ObjCProperty l-value; the
|
||||
/// result will generally be an r-value, but could be an ordinary
|
||||
/// gl-value if the property reference is to an implicit property
|
||||
/// for a method that returns a reference type.
|
||||
CK_GetObjCProperty,
|
||||
|
||||
/// CK_NoOp - Used for const_cast.
|
||||
/// CK_NoOp - A conversion which does not affect the type other than
|
||||
/// (possibly) adding qualifiers.
|
||||
/// int -> int
|
||||
/// char** -> const char * const *
|
||||
CK_NoOp,
|
||||
|
||||
/// CK_BaseToDerived - Base to derived class casts.
|
||||
/// CK_BaseToDerived - A conversion from a C++ class pointer/reference
|
||||
/// to a derived class pointer/reference.
|
||||
/// B *b = static_cast<B*>(a);
|
||||
CK_BaseToDerived,
|
||||
|
||||
/// CK_DerivedToBase - Derived to base class casts.
|
||||
/// CK_DerivedToBase - A conversion from a C++ class pointer
|
||||
/// to a base class pointer.
|
||||
/// A *a = new B();
|
||||
CK_DerivedToBase,
|
||||
|
||||
/// CK_UncheckedDerivedToBase - Derived to base class casts that
|
||||
/// assume that the derived pointer is not null.
|
||||
/// CK_UncheckedDerivedToBase - A conversion from a C++ class
|
||||
/// pointer/reference to a base class that can assume that the
|
||||
/// derived pointer is not null.
|
||||
/// const A &a = B();
|
||||
/// b->method_from_a();
|
||||
CK_UncheckedDerivedToBase,
|
||||
|
||||
/// CK_Dynamic - Dynamic cast.
|
||||
/// CK_Dynamic - A C++ dynamic_cast.
|
||||
CK_Dynamic,
|
||||
|
||||
/// CK_ToUnion - Cast to union (GCC extension).
|
||||
/// CK_ToUnion - The GCC cast-to-union extension.
|
||||
/// int -> union { int x; float y; }
|
||||
/// float -> union { int x; float y; }
|
||||
CK_ToUnion,
|
||||
|
||||
/// CK_ArrayToPointerDecay - Array to pointer decay.
|
||||
/// int[10] -> int*
|
||||
/// char[5][6] -> char(*)[6]
|
||||
CK_ArrayToPointerDecay,
|
||||
|
||||
// CK_FunctionToPointerDecay - Function to pointer decay.
|
||||
/// CK_FunctionToPointerDecay - Function to pointer decay.
|
||||
/// void(int) -> void(*)(int)
|
||||
CK_FunctionToPointerDecay,
|
||||
|
||||
/// CK_NullToMemberPointer - Null pointer to member pointer.
|
||||
/// CK_NullToPointer - Null pointer constant to pointer, ObjC
|
||||
/// pointer, or block pointer.
|
||||
/// (void*) 0
|
||||
/// void (^block)() = 0;
|
||||
CK_NullToPointer,
|
||||
|
||||
/// CK_NullToMemberPointer - Null pointer constant to member pointer.
|
||||
/// int A::*mptr = 0;
|
||||
/// int (A::*fptr)(int) = nullptr;
|
||||
CK_NullToMemberPointer,
|
||||
|
||||
/// CK_BaseToDerivedMemberPointer - Member pointer in base class to
|
||||
/// member pointer in derived class.
|
||||
/// int B::*mptr = &A::member;
|
||||
CK_BaseToDerivedMemberPointer,
|
||||
|
||||
/// CK_DerivedToBaseMemberPointer - Member pointer in derived class to
|
||||
/// member pointer in base class.
|
||||
/// int A::*mptr = static_cast<int A::*>(&B::member);
|
||||
CK_DerivedToBaseMemberPointer,
|
||||
|
||||
/// CK_UserDefinedConversion - Conversion using a user defined type
|
||||
/// conversion function.
|
||||
CK_UserDefinedConversion,
|
||||
|
||||
/// CK_ConstructorConversion - Conversion by constructor
|
||||
CK_ConstructorConversion,
|
||||
|
||||
/// CK_IntegralToPointer - Integral to pointer
|
||||
CK_IntegralToPointer,
|
||||
|
||||
/// CK_PointerToIntegral - Pointer to integral
|
||||
CK_PointerToIntegral,
|
||||
|
||||
/// CK_ToVoid - Cast to void.
|
||||
CK_ToVoid,
|
||||
|
||||
/// CK_VectorSplat - Casting from an integer/floating type to an extended
|
||||
/// vector type with the same element type as the src type. Splats the
|
||||
/// src expression into the destination expression.
|
||||
CK_VectorSplat,
|
||||
|
||||
/// CK_IntegralCast - Casting between integral types of different size.
|
||||
CK_IntegralCast,
|
||||
|
||||
/// CK_IntegralToFloating - Integral to floating point.
|
||||
CK_IntegralToFloating,
|
||||
|
||||
/// CK_FloatingToIntegral - Floating point to integral.
|
||||
CK_FloatingToIntegral,
|
||||
|
||||
/// CK_FloatingCast - Casting between floating types of different size.
|
||||
CK_FloatingCast,
|
||||
|
||||
/// CK_MemberPointerToBoolean - Member pointer to boolean
|
||||
/// CK_MemberPointerToBoolean - Member pointer to boolean. A check
|
||||
/// against the null member pointer.
|
||||
CK_MemberPointerToBoolean,
|
||||
|
||||
/// CK_AnyPointerToObjCPointerCast - Casting any pointer to objective-c
|
||||
/// pointer
|
||||
/// CK_UserDefinedConversion - Conversion using a user defined type
|
||||
/// conversion function.
|
||||
/// struct A { operator int(); }; int i = int(A());
|
||||
CK_UserDefinedConversion,
|
||||
|
||||
/// CK_ConstructorConversion - Conversion by constructor.
|
||||
/// struct A { A(int); }; A a = A(10);
|
||||
CK_ConstructorConversion,
|
||||
|
||||
/// CK_IntegralToPointer - Integral to pointer. A special kind of
|
||||
/// reinterpreting conversion. Applies to normal, ObjC, and block
|
||||
/// pointers.
|
||||
/// (char*) 0x1001aab0
|
||||
/// reinterpret_cast<int*>(0)
|
||||
CK_IntegralToPointer,
|
||||
|
||||
/// CK_PointerToIntegral - Pointer to integral. A special kind of
|
||||
/// reinterpreting conversion. Applies to normal, ObjC, and block
|
||||
/// pointers.
|
||||
/// (intptr_t) "help!"
|
||||
CK_PointerToIntegral,
|
||||
|
||||
/// CK_PointerToBoolean - Pointer to boolean conversion. A check
|
||||
/// against null. Applies to normal, ObjC, and block pointers.
|
||||
CK_PointerToBoolean,
|
||||
|
||||
/// CK_ToVoid - Cast to void, discarding the computed value.
|
||||
/// (void) malloc(2048)
|
||||
CK_ToVoid,
|
||||
|
||||
/// CK_VectorSplat - A conversion from an arithmetic type to a
|
||||
/// vector of that element type. Fills all elements ("splats") with
|
||||
/// the source value.
|
||||
/// __attribute__((ext_vector_type(4))) int v = 5;
|
||||
CK_VectorSplat,
|
||||
|
||||
/// CK_IntegralCast - A cast between integral types (other than to
|
||||
/// boolean). Variously a bitcast, a truncation, a sign-extension,
|
||||
/// or a zero-extension.
|
||||
/// long l = 5;
|
||||
/// (unsigned) i
|
||||
CK_IntegralCast,
|
||||
|
||||
/// CK_IntegralToBoolean - Integral to boolean. A check against zero.
|
||||
/// (bool) i
|
||||
CK_IntegralToBoolean,
|
||||
|
||||
/// CK_IntegralToFloating - Integral to floating point.
|
||||
/// float f = i;
|
||||
CK_IntegralToFloating,
|
||||
|
||||
/// CK_FloatingToIntegral - Floating point to integral. Rounds
|
||||
/// towards zero, discarding any fractional component.
|
||||
/// (int) f
|
||||
CK_FloatingToIntegral,
|
||||
|
||||
/// CK_FloatingToBoolean - Floating point to boolean.
|
||||
/// (bool) f
|
||||
CK_FloatingToBoolean,
|
||||
|
||||
/// CK_FloatingCast - Casting between floating types of different size.
|
||||
/// (double) f
|
||||
/// (float) ld
|
||||
CK_FloatingCast,
|
||||
|
||||
/// CK_AnyPointerToObjCPointerCast - Casting any other pointer kind
|
||||
/// to an Objective-C pointer.
|
||||
CK_AnyPointerToObjCPointerCast,
|
||||
|
||||
/// CK_AnyPointerToBlockPointerCast - Casting any pointer to block
|
||||
/// pointer
|
||||
/// CK_AnyPointerToBlockPointerCast - Casting any other pointer kind
|
||||
/// to a block pointer.
|
||||
CK_AnyPointerToBlockPointerCast,
|
||||
|
||||
/// \brief Converting between two Objective-C object types, which
|
||||
/// can occur when performing reference binding to an Objective-C
|
||||
/// object.
|
||||
CK_ObjCObjectLValueCast
|
||||
CK_ObjCObjectLValueCast,
|
||||
|
||||
/// \brief A conversion of a floating point real to a floating point
|
||||
/// complex of the original type. Injects the value as the real
|
||||
/// component with a zero imaginary component.
|
||||
/// float -> _Complex float
|
||||
CK_FloatingRealToComplex,
|
||||
|
||||
/// \brief Converts a floating point complex to floating point real
|
||||
/// of the source's element type. Just discards the imaginary
|
||||
/// component.
|
||||
/// _Complex long double -> long double
|
||||
CK_FloatingComplexToReal,
|
||||
|
||||
/// \brief Converts a floating point complex to bool by comparing
|
||||
/// against 0+0i.
|
||||
CK_FloatingComplexToBoolean,
|
||||
|
||||
/// \brief Converts between different floating point complex types.
|
||||
/// _Complex float -> _Complex double
|
||||
CK_FloatingComplexCast,
|
||||
|
||||
/// \brief Converts from a floating complex to an integral complex.
|
||||
/// _Complex float -> _Complex int
|
||||
CK_FloatingComplexToIntegralComplex,
|
||||
|
||||
/// \brief Converts from an integral real to an integral complex
|
||||
/// whose element type matches the source. Injects the value as
|
||||
/// the real component with a zero imaginary component.
|
||||
/// long -> _Complex long
|
||||
CK_IntegralRealToComplex,
|
||||
|
||||
/// \brief Converts an integral complex to an integral real of the
|
||||
/// source's element type by discarding the imaginary component.
|
||||
/// _Complex short -> short
|
||||
CK_IntegralComplexToReal,
|
||||
|
||||
/// \brief Converts an integral complex to bool by comparing against
|
||||
/// 0+0i.
|
||||
CK_IntegralComplexToBoolean,
|
||||
|
||||
/// \brief Converts between different integral complex types.
|
||||
/// _Complex char -> _Complex long long
|
||||
/// _Complex unsigned int -> _Complex signed int
|
||||
CK_IntegralComplexCast,
|
||||
|
||||
/// \brief Converts from an integral complex to a floating complex.
|
||||
/// _Complex unsigned -> _Complex float
|
||||
CK_IntegralComplexToFloatingComplex
|
||||
};
|
||||
|
||||
#define CK_Invalid ((CastKind) -1)
|
||||
|
||||
enum BinaryOperatorKind {
|
||||
// Operators listed in order of precedence.
|
||||
|
@ -24,8 +24,14 @@ class ParentMap {
|
||||
ParentMap(Stmt* ASTRoot);
|
||||
~ParentMap();
|
||||
|
||||
/// \brief Adds and/or updates the parent/child-relations of the complete
|
||||
/// stmt tree of S. All children of S including indirect descendants are
|
||||
/// visited and updated or inserted but not the parents of S.
|
||||
void addStmt(Stmt* S);
|
||||
|
||||
Stmt *getParent(Stmt*) const;
|
||||
Stmt *getParentIgnoreParens(Stmt *) const;
|
||||
Stmt *getParentIgnoreParenCasts(Stmt *) const;
|
||||
|
||||
const Stmt *getParent(const Stmt* S) const {
|
||||
return getParent(const_cast<Stmt*>(S));
|
||||
@ -35,6 +41,10 @@ class ParentMap {
|
||||
return getParentIgnoreParens(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
const Stmt *getParentIgnoreParenCasts(const Stmt *S) const {
|
||||
return getParentIgnoreParenCasts(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
bool hasParent(Stmt* S) const {
|
||||
return getParent(S) != 0;
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H
|
||||
#define LLVM_CLANG_AST_PRETTY_PRINTER_H
|
||||
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
@ -44,7 +46,7 @@ struct PrintingPolicy {
|
||||
unsigned Indentation : 8;
|
||||
|
||||
/// \brief What language we're printing.
|
||||
const LangOptions &LangOpts;
|
||||
const LangOptions LangOpts;
|
||||
|
||||
/// \brief Whether we should suppress printing of the actual specifiers for
|
||||
/// the given type or declaration.
|
||||
|
@ -14,8 +14,9 @@
|
||||
#ifndef LLVM_CLANG_AST_LAYOUTINFO_H
|
||||
#define LLVM_CLANG_AST_LAYOUTINFO_H
|
||||
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
|
||||
namespace clang {
|
||||
@ -32,93 +33,41 @@ namespace clang {
|
||||
/// ObjCInterfaceDecl. FIXME - Find appropriate name.
|
||||
/// These objects are managed by ASTContext.
|
||||
class ASTRecordLayout {
|
||||
/// Size - Size of record in bits.
|
||||
uint64_t Size;
|
||||
/// Size - Size of record in characters.
|
||||
CharUnits Size;
|
||||
|
||||
/// DataSize - Size of record in bits without tail padding.
|
||||
uint64_t DataSize;
|
||||
/// DataSize - Size of record in characters without tail padding.
|
||||
CharUnits DataSize;
|
||||
|
||||
/// FieldOffsets - Array of field offsets in bits.
|
||||
uint64_t *FieldOffsets;
|
||||
|
||||
// Alignment - Alignment of record in bits.
|
||||
unsigned Alignment;
|
||||
// Alignment - Alignment of record in characters.
|
||||
CharUnits Alignment;
|
||||
|
||||
// FieldCount - Number of fields.
|
||||
unsigned FieldCount;
|
||||
|
||||
public:
|
||||
/// PrimaryBaseInfo - Contains info about a primary base.
|
||||
struct PrimaryBaseInfo {
|
||||
PrimaryBaseInfo() {}
|
||||
|
||||
PrimaryBaseInfo(const CXXRecordDecl *Base, bool IsVirtual)
|
||||
: Value(Base, Base && IsVirtual) {}
|
||||
|
||||
/// Value - Points to the primary base. The single-bit value
|
||||
/// will be non-zero when the primary base is virtual.
|
||||
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Value;
|
||||
|
||||
/// getBase - Returns the primary base.
|
||||
const CXXRecordDecl *getBase() const { return Value.getPointer(); }
|
||||
|
||||
/// isVirtual - Returns whether the primary base is virtual or not.
|
||||
bool isVirtual() const { return Value.getInt(); }
|
||||
|
||||
friend bool operator==(const PrimaryBaseInfo &X, const PrimaryBaseInfo &Y) {
|
||||
return X.Value == Y.Value;
|
||||
}
|
||||
};
|
||||
|
||||
/// primary_base_info_iterator - An iterator for iterating the primary base
|
||||
/// class chain.
|
||||
class primary_base_info_iterator {
|
||||
/// Current - The current base class info.
|
||||
PrimaryBaseInfo Current;
|
||||
|
||||
public:
|
||||
primary_base_info_iterator() {}
|
||||
primary_base_info_iterator(PrimaryBaseInfo Info) : Current(Info) {}
|
||||
|
||||
const PrimaryBaseInfo &operator*() const { return Current; }
|
||||
|
||||
primary_base_info_iterator& operator++() {
|
||||
const CXXRecordDecl *RD = Current.getBase();
|
||||
Current = RD->getASTContext().getASTRecordLayout(RD).getPrimaryBaseInfo();
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend bool operator==(const primary_base_info_iterator &X,
|
||||
const primary_base_info_iterator &Y) {
|
||||
return X.Current == Y.Current;
|
||||
}
|
||||
friend bool operator!=(const primary_base_info_iterator &X,
|
||||
const primary_base_info_iterator &Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/// CXXRecordLayoutInfo - Contains C++ specific layout information.
|
||||
struct CXXRecordLayoutInfo {
|
||||
/// NonVirtualSize - The non-virtual size (in bits) of an object, which is
|
||||
/// NonVirtualSize - The non-virtual size (in chars) of an object, which is
|
||||
/// the size of the object without virtual bases.
|
||||
uint64_t NonVirtualSize;
|
||||
CharUnits NonVirtualSize;
|
||||
|
||||
/// NonVirtualAlign - The non-virtual alignment (in bits) of an object,
|
||||
/// NonVirtualAlign - The non-virtual alignment (in chars) of an object,
|
||||
/// which is the alignment of the object without virtual bases.
|
||||
uint64_t NonVirtualAlign;
|
||||
CharUnits NonVirtualAlign;
|
||||
|
||||
/// SizeOfLargestEmptySubobject - The size of the largest empty subobject
|
||||
/// (either a base or a member). Will be zero if the class doesn't contain
|
||||
/// any empty subobjects.
|
||||
uint64_t SizeOfLargestEmptySubobject;
|
||||
CharUnits SizeOfLargestEmptySubobject;
|
||||
|
||||
/// PrimaryBase - The primary base info for this record.
|
||||
PrimaryBaseInfo PrimaryBase;
|
||||
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
|
||||
|
||||
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
|
||||
typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy;
|
||||
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
|
||||
|
||||
/// BaseOffsets - Contains a map from base classes to their offset.
|
||||
BaseOffsetsMapTy BaseOffsets;
|
||||
@ -133,35 +82,35 @@ class ASTRecordLayout {
|
||||
|
||||
friend class ASTContext;
|
||||
|
||||
ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignment,
|
||||
unsigned datasize, const uint64_t *fieldoffsets,
|
||||
ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
|
||||
CharUnits datasize, const uint64_t *fieldoffsets,
|
||||
unsigned fieldcount);
|
||||
|
||||
// Constructor for C++ records.
|
||||
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
|
||||
ASTRecordLayout(ASTContext &Ctx,
|
||||
uint64_t size, unsigned alignment, uint64_t datasize,
|
||||
ASTRecordLayout(const ASTContext &Ctx,
|
||||
CharUnits size, CharUnits alignment, CharUnits datasize,
|
||||
const uint64_t *fieldoffsets, unsigned fieldcount,
|
||||
uint64_t nonvirtualsize, unsigned nonvirtualalign,
|
||||
uint64_t SizeOfLargestEmptySubobject,
|
||||
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
|
||||
CharUnits SizeOfLargestEmptySubobject,
|
||||
const CXXRecordDecl *PrimaryBase,
|
||||
bool PrimaryBaseIsVirtual,
|
||||
bool IsPrimaryBaseVirtual,
|
||||
const BaseOffsetsMapTy& BaseOffsets,
|
||||
const BaseOffsetsMapTy& VBaseOffsets);
|
||||
|
||||
~ASTRecordLayout() {}
|
||||
|
||||
void Destroy(ASTContext &Ctx);
|
||||
|
||||
|
||||
ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT
|
||||
void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT
|
||||
public:
|
||||
|
||||
/// getAlignment - Get the record alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
/// getAlignment - Get the record alignment in characters.
|
||||
CharUnits getAlignment() const { return Alignment; }
|
||||
|
||||
/// getSize - Get the record size in bits.
|
||||
uint64_t getSize() const { return Size; }
|
||||
/// getSize - Get the record size in characters.
|
||||
CharUnits getSize() const { return Size; }
|
||||
|
||||
/// getFieldCount - Get the number of fields in the layout.
|
||||
unsigned getFieldCount() const { return FieldCount; }
|
||||
@ -174,76 +123,82 @@ class ASTRecordLayout {
|
||||
}
|
||||
|
||||
/// getDataSize() - Get the record data size, which is the record size
|
||||
/// without tail padding, in bits.
|
||||
uint64_t getDataSize() const {
|
||||
/// without tail padding, in characters.
|
||||
CharUnits getDataSize() const {
|
||||
return DataSize;
|
||||
}
|
||||
|
||||
/// getNonVirtualSize - Get the non-virtual size (in bits) of an object,
|
||||
/// getNonVirtualSize - Get the non-virtual size (in chars) of an object,
|
||||
/// which is the size of the object without virtual bases.
|
||||
uint64_t getNonVirtualSize() const {
|
||||
CharUnits getNonVirtualSize() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->NonVirtualSize;
|
||||
}
|
||||
|
||||
/// getNonVirtualSize - Get the non-virtual alignment (in bits) of an object,
|
||||
/// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object,
|
||||
/// which is the alignment of the object without virtual bases.
|
||||
unsigned getNonVirtualAlign() const {
|
||||
CharUnits getNonVirtualAlign() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->NonVirtualAlign;
|
||||
}
|
||||
|
||||
/// getPrimaryBaseInfo - Get the primary base info.
|
||||
const PrimaryBaseInfo &getPrimaryBaseInfo() const {
|
||||
/// getPrimaryBase - Get the primary base for this record.
|
||||
const CXXRecordDecl *getPrimaryBase() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->PrimaryBase;
|
||||
return CXXInfo->PrimaryBase.getPointer();
|
||||
}
|
||||
|
||||
// FIXME: Migrate off of this function and use getPrimaryBaseInfo directly.
|
||||
const CXXRecordDecl *getPrimaryBase() const {
|
||||
return getPrimaryBaseInfo().getBase();
|
||||
/// isPrimaryBaseVirtual - Get whether the primary base for this record
|
||||
/// is virtual or not.
|
||||
bool isPrimaryBaseVirtual() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->PrimaryBase.getInt();
|
||||
}
|
||||
|
||||
// FIXME: Migrate off of this function and use getPrimaryBaseInfo directly.
|
||||
bool getPrimaryBaseWasVirtual() const {
|
||||
return getPrimaryBaseInfo().isVirtual();
|
||||
}
|
||||
|
||||
/// getBaseClassOffset - Get the offset, in bits, for the given base class.
|
||||
uint64_t getBaseClassOffset(const CXXRecordDecl *Base) const {
|
||||
/// getBaseClassOffset - Get the offset, in chars, for the given base class.
|
||||
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
|
||||
|
||||
return CXXInfo->BaseOffsets[Base];
|
||||
}
|
||||
|
||||
/// getVBaseClassOffset - Get the offset, in bits, for the given base class.
|
||||
uint64_t getVBaseClassOffset(const CXXRecordDecl *VBase) const {
|
||||
/// getVBaseClassOffset - Get the offset, in chars, for the given base class.
|
||||
CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
|
||||
|
||||
return CXXInfo->VBaseOffsets[VBase];
|
||||
}
|
||||
|
||||
uint64_t getSizeOfLargestEmptySubobject() const {
|
||||
|
||||
/// getBaseClassOffsetInBits - Get the offset, in bits, for the given
|
||||
/// base class.
|
||||
uint64_t getBaseClassOffsetInBits(const CXXRecordDecl *Base) const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
|
||||
|
||||
return getBaseClassOffset(Base).getQuantity() *
|
||||
Base->getASTContext().getCharWidth();
|
||||
}
|
||||
|
||||
/// getVBaseClassOffsetInBits - Get the offset, in bits, for the given
|
||||
/// base class.
|
||||
uint64_t getVBaseClassOffsetInBits(const CXXRecordDecl *VBase) const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
|
||||
|
||||
return getVBaseClassOffset(VBase).getQuantity() *
|
||||
VBase->getASTContext().getCharWidth();
|
||||
}
|
||||
|
||||
CharUnits getSizeOfLargestEmptySubobject() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
return CXXInfo->SizeOfLargestEmptySubobject;
|
||||
}
|
||||
|
||||
primary_base_info_iterator primary_base_begin() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return primary_base_info_iterator(getPrimaryBaseInfo());
|
||||
}
|
||||
|
||||
primary_base_info_iterator primary_base_end() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return primary_base_info_iterator();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -143,6 +143,10 @@ class RecursiveASTVisitor {
|
||||
/// \brief Return whether this visitor should recurse into
|
||||
/// template instantiations.
|
||||
bool shouldVisitTemplateInstantiations() const { return false; }
|
||||
|
||||
/// \brief Return whether this visitor should recurse into the types of
|
||||
/// TypeLocs.
|
||||
bool shouldWalkTypesOfTypeLocs() const { return true; }
|
||||
|
||||
/// \brief Recursively visit a statement or expression, by
|
||||
/// dispatching to Traverse*() based on the argument's dynamic type.
|
||||
@ -211,7 +215,7 @@ class RecursiveASTVisitor {
|
||||
/// be overridden for clients that need access to the name.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
bool TraverseConstructorInitializer(CXXBaseOrMemberInitializer *Init);
|
||||
bool TraverseConstructorInitializer(CXXCtorInitializer *Init);
|
||||
|
||||
// ---- Methods on Stmts ----
|
||||
|
||||
@ -368,7 +372,7 @@ class RecursiveASTVisitor {
|
||||
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
|
||||
bool TraverseClassInstantiations(ClassTemplateDecl* D, Decl *Pattern);
|
||||
bool TraverseFunctionInstantiations(FunctionTemplateDecl* D) ;
|
||||
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
|
||||
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
|
||||
unsigned Count);
|
||||
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
|
||||
bool TraverseRecordHelper(RecordDecl *D);
|
||||
@ -393,7 +397,7 @@ bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
|
||||
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
|
||||
switch (BinOp->getOpcode()) {
|
||||
#define OPERATOR(NAME) \
|
||||
case BO_##NAME: DISPATCH(Bin##PtrMemD, BinaryOperator, S);
|
||||
case BO_##NAME: DISPATCH(Bin##NAME, BinaryOperator, S);
|
||||
|
||||
BINOP_LIST()
|
||||
#undef OPERATOR
|
||||
@ -438,7 +442,8 @@ bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
|
||||
switch (T->getTypeClass()) {
|
||||
#define ABSTRACT_TYPE(CLASS, BASE)
|
||||
#define TYPE(CLASS, BASE) \
|
||||
case Type::CLASS: DISPATCH(CLASS##Type, CLASS##Type, T.getTypePtr());
|
||||
case Type::CLASS: DISPATCH(CLASS##Type, CLASS##Type, \
|
||||
const_cast<Type*>(T.getTypePtr()));
|
||||
#include "clang/AST/TypeNodes.def"
|
||||
}
|
||||
|
||||
@ -531,7 +536,9 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
|
||||
return getDerived().TraverseType(Arg.getAsType());
|
||||
|
||||
case TemplateArgument::Template:
|
||||
return getDerived().TraverseTemplateName(Arg.getAsTemplate());
|
||||
case TemplateArgument::TemplateExpansion:
|
||||
return getDerived().TraverseTemplateName(
|
||||
Arg.getAsTemplateOrTemplatePattern());
|
||||
|
||||
case TemplateArgument::Expression:
|
||||
return getDerived().TraverseStmt(Arg.getAsExpr());
|
||||
@ -566,7 +573,9 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
|
||||
}
|
||||
|
||||
case TemplateArgument::Template:
|
||||
return getDerived().TraverseTemplateName(Arg.getAsTemplate());
|
||||
case TemplateArgument::TemplateExpansion:
|
||||
return getDerived().TraverseTemplateName(
|
||||
Arg.getAsTemplateOrTemplatePattern());
|
||||
|
||||
case TemplateArgument::Expression:
|
||||
return getDerived().TraverseStmt(ArgLoc.getSourceExpression());
|
||||
@ -592,7 +601,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments(
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
|
||||
CXXBaseOrMemberInitializer *Init) {
|
||||
CXXCtorInitializer *Init) {
|
||||
// FIXME: recurse on TypeLoc of the base initializer if isBaseInitializer()?
|
||||
if (Init->isWritten())
|
||||
TRY_TO(TraverseStmt(Init->getInit()));
|
||||
@ -706,10 +715,15 @@ DEF_TRAVERSE_TYPE(DecltypeType, {
|
||||
TRY_TO(TraverseStmt(T->getUnderlyingExpr()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(AutoType, {
|
||||
TRY_TO(TraverseType(T->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(RecordType, { })
|
||||
DEF_TRAVERSE_TYPE(EnumType, { })
|
||||
DEF_TRAVERSE_TYPE(TemplateTypeParmType, { })
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { })
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { })
|
||||
|
||||
DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateName(T->getTemplateName()));
|
||||
@ -718,6 +732,14 @@ DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
|
||||
|
||||
DEF_TRAVERSE_TYPE(InjectedClassNameType, { })
|
||||
|
||||
DEF_TRAVERSE_TYPE(AttributedType, {
|
||||
TRY_TO(TraverseType(T->getModifiedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(ParenType, {
|
||||
TRY_TO(TraverseType(T->getInnerType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(ElaboratedType, {
|
||||
if (T->getQualifier()) {
|
||||
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
|
||||
@ -734,6 +756,10 @@ DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(PackExpansionType, {
|
||||
TRY_TO(TraverseType(T->getPattern()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(ObjCInterfaceType, { })
|
||||
|
||||
DEF_TRAVERSE_TYPE(ObjCObjectType, {
|
||||
@ -752,14 +778,15 @@ DEF_TRAVERSE_TYPE(ObjCObjectPointerType, {
|
||||
// ----------------- TypeLoc traversal -----------------
|
||||
|
||||
// This macro makes available a variable TL, the passed-in TypeLoc.
|
||||
// It calls WalkUpFrom* for the Type in the given TypeLoc, in addition
|
||||
// to WalkUpFrom* for the TypeLoc itself, such that existing clients
|
||||
// that override the WalkUpFrom*Type() and/or Visit*Type() methods
|
||||
// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc,
|
||||
// in addition to WalkUpFrom* for the TypeLoc itself, such that existing
|
||||
// clients that override the WalkUpFrom*Type() and/or Visit*Type() methods
|
||||
// continue to work.
|
||||
#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \
|
||||
template<typename Derived> \
|
||||
bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc(TYPE##Loc TL) { \
|
||||
TRY_TO(WalkUpFrom##TYPE(TL.getTypePtr())); \
|
||||
if (getDerived().shouldWalkTypesOfTypeLocs()) \
|
||||
TRY_TO(WalkUpFrom##TYPE(const_cast<TYPE*>(TL.getTypePtr()))); \
|
||||
TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \
|
||||
{ CODE; } \
|
||||
return true; \
|
||||
@ -867,22 +894,16 @@ DEF_TRAVERSE_TYPELOC(FunctionNoProtoType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getResultLoc()));
|
||||
})
|
||||
|
||||
// FIXME: location of arguments, exception specifications (attributes?)
|
||||
// Note that we have the ParmVarDecl's here. Do we want to use them?
|
||||
// FIXME: location of exception specifications (attributes?)
|
||||
DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getResultLoc()));
|
||||
|
||||
FunctionProtoType *T = TL.getTypePtr();
|
||||
/*
|
||||
const FunctionProtoType *T = TL.getTypePtr();
|
||||
|
||||
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
|
||||
TRY_TO(TraverseDecl(TL.getArg(I)));
|
||||
}
|
||||
*/
|
||||
for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
|
||||
AEnd = T->arg_type_end();
|
||||
A != AEnd; ++A) {
|
||||
TRY_TO(TraverseType(*A));
|
||||
}
|
||||
|
||||
for (FunctionProtoType::exception_iterator E = T->exception_begin(),
|
||||
EEnd = T->exception_end();
|
||||
E != EEnd; ++E) {
|
||||
@ -906,10 +927,15 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, {
|
||||
TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(AutoType, {
|
||||
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(RecordType, { })
|
||||
DEF_TRAVERSE_TYPELOC(EnumType, { })
|
||||
DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, { })
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { })
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { })
|
||||
|
||||
// FIXME: use the loc for the template name?
|
||||
DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
|
||||
@ -921,6 +947,14 @@ DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(InjectedClassNameType, { })
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(ParenType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getInnerLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(AttributedType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getModifiedLoc()));
|
||||
})
|
||||
|
||||
// FIXME: use the sourceloc on qualifier?
|
||||
DEF_TRAVERSE_TYPELOC(ElaboratedType, {
|
||||
if (TL.getTypePtr()->getQualifier()) {
|
||||
@ -941,6 +975,10 @@ DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, {
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(PackExpansionType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getPatternLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, { })
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(ObjCObjectType, {
|
||||
@ -1001,11 +1039,18 @@ DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(FriendDecl, {
|
||||
TRY_TO(TraverseDecl(D->getFriendDecl()));
|
||||
// Friend is either decl or a type.
|
||||
if (D->getFriendType())
|
||||
TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
|
||||
else
|
||||
TRY_TO(TraverseDecl(D->getFriendDecl()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(FriendTemplateDecl, {
|
||||
TRY_TO(TraverseDecl(D->getFriendDecl()));
|
||||
if (D->getFriendType())
|
||||
TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
|
||||
else
|
||||
TRY_TO(TraverseDecl(D->getFriendDecl()));
|
||||
for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) {
|
||||
TemplateParameterList *TPL = D->getTemplateParameterList(I);
|
||||
for (TemplateParameterList::iterator ITPL = TPL->begin(),
|
||||
@ -1051,6 +1096,11 @@ DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
|
||||
return true;
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(LabelDecl, {
|
||||
// There is no code in a LabelDecl.
|
||||
})
|
||||
|
||||
|
||||
DEF_TRAVERSE_DECL(NamespaceDecl, {
|
||||
// Code in an unnamed namespace shows up automatically in
|
||||
// decls_begin()/decls_end(). Thus we don't need to recurse on
|
||||
@ -1082,7 +1132,9 @@ DEF_TRAVERSE_DECL(ObjCProtocolDecl, {
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCMethodDecl, {
|
||||
// FIXME: implement
|
||||
// We don't traverse nodes in param_begin()/param_end(), as they
|
||||
// appear in decls_begin()/decls_end() and thus are handled.
|
||||
TRY_TO(TraverseStmt(D->getBody()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
||||
@ -1175,7 +1227,7 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, {
|
||||
if (D->isThisDeclarationADefinition())
|
||||
TRY_TO(TraverseClassInstantiations(D, D));
|
||||
}
|
||||
|
||||
|
||||
// Note that getInstantiatedFromMemberTemplate() is just a link
|
||||
// from a template instantiation back to the template from which
|
||||
// it was instantiated, and thus should not be traversed.
|
||||
@ -1208,10 +1260,10 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
|
||||
assert(false && "Unknown specialization kind.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
|
||||
TRY_TO(TraverseDecl(D->getTemplatedDecl()));
|
||||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
||||
@ -1251,7 +1303,7 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(TypedefDecl, {
|
||||
TRY_TO(TraverseType(D->getUnderlyingType()));
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
// We shouldn't traverse D->getTypeForDecl(); it's a result of
|
||||
// declaring the typedef, not something that was written in the
|
||||
// source.
|
||||
@ -1282,11 +1334,7 @@ bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(
|
||||
RecordDecl *D) {
|
||||
// We shouldn't traverse D->getTypeForDecl(); it's a result of
|
||||
// declaring the type, not something that was written in the source.
|
||||
//
|
||||
// The anonymous struct or union object is the variable or field
|
||||
// whose type is the anonymous struct or union. We shouldn't
|
||||
// traverse D->getAnonymousStructOrUnionObject(), as it's not
|
||||
// something that is explicitly written in the source.
|
||||
|
||||
TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
|
||||
return true;
|
||||
}
|
||||
@ -1380,6 +1428,8 @@ DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, {
|
||||
TRY_TO(TraverseNestedNameSpecifier(D->getTargetNestedNameSpecifier()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(IndirectFieldDecl, {})
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) {
|
||||
TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
|
||||
@ -1412,47 +1462,11 @@ template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
|
||||
TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
|
||||
|
||||
// Visit the function type itself, which can be either
|
||||
// FunctionNoProtoType or FunctionProtoType, or a typedef. If it's
|
||||
// not a Function*ProtoType, then it can't have a body or arguments,
|
||||
// so we have to do less work.
|
||||
Type *FuncType = D->getType().getTypePtr();
|
||||
if (FunctionProtoType *FuncProto = dyn_cast<FunctionProtoType>(FuncType)) {
|
||||
if (D->isThisDeclarationADefinition()) {
|
||||
// Don't call Traverse*, or the result type and parameter types
|
||||
// will be double counted.
|
||||
TRY_TO(WalkUpFromFunctionProtoType(FuncProto));
|
||||
} else {
|
||||
// This works around a bug in Clang that does not add the parameters
|
||||
// to decls_begin/end for function declarations (as opposed to
|
||||
// definitions):
|
||||
// http://llvm.org/PR7442
|
||||
// We work around this here by traversing the function type.
|
||||
// This isn't perfect because we don't traverse the default
|
||||
// values, if any. It also may not interact great with
|
||||
// templates. But it's the best we can do until the bug is
|
||||
// fixed.
|
||||
// FIXME: replace the entire 'if' statement with
|
||||
// TRY_TO(WalkUpFromFunctionProtoType(FuncProto));
|
||||
// when the bug is fixed.
|
||||
TRY_TO(TraverseFunctionProtoType(FuncProto));
|
||||
return true;
|
||||
}
|
||||
} else if (FunctionNoProtoType *FuncNoProto =
|
||||
dyn_cast<FunctionNoProtoType>(FuncType)) {
|
||||
// Don't call Traverse*, or the result type will be double
|
||||
// counted.
|
||||
TRY_TO(WalkUpFromFunctionNoProtoType(FuncNoProto));
|
||||
} else { // a typedef type, or who knows what
|
||||
assert(!D->isThisDeclarationADefinition() && "Unexpected function type");
|
||||
TRY_TO(TraverseType(D->getType()));
|
||||
return true;
|
||||
}
|
||||
|
||||
TRY_TO(TraverseType(D->getResultType()));
|
||||
|
||||
// If we're an explicit template specialization, iterate over the
|
||||
// template args that were explicitly specified.
|
||||
// template args that were explicitly specified. If we were doing
|
||||
// this in typing order, we'd do it between the return type and
|
||||
// the function args, but both are handled by the FunctionTypeLoc
|
||||
// above, so we have to choose one side. I've decided to do before.
|
||||
if (const FunctionTemplateSpecializationInfo *FTSI =
|
||||
D->getTemplateSpecializationInfo()) {
|
||||
if (FTSI->getTemplateSpecializationKind() != TSK_Undeclared &&
|
||||
@ -1467,28 +1481,11 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
|
||||
}
|
||||
}
|
||||
|
||||
for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end();
|
||||
I != E; ++I) {
|
||||
TRY_TO(TraverseDecl(*I));
|
||||
}
|
||||
|
||||
if (FunctionProtoType *FuncProto = dyn_cast<FunctionProtoType>(FuncType)) {
|
||||
if (D->isThisDeclarationADefinition()) {
|
||||
// This would be visited if we called TraverseType(D->getType())
|
||||
// above, but we don't (at least, not in the
|
||||
// declaration-is-a-definition case), in order to avoid duplicate
|
||||
// visiting for parameters. (We need to check parameters here,
|
||||
// rather than letting D->getType() do it, so we visit default
|
||||
// parameter values). So we need to re-do some of the work the
|
||||
// type would do.
|
||||
for (FunctionProtoType::exception_iterator
|
||||
E = FuncProto->exception_begin(),
|
||||
EEnd = FuncProto->exception_end();
|
||||
E != EEnd; ++E) {
|
||||
TRY_TO(TraverseType(*E));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Visit the function type itself, which can be either
|
||||
// FunctionNoProtoType or FunctionProtoType, or a typedef. This
|
||||
// also covers the return type and the function parameters,
|
||||
// including exception specifications.
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
|
||||
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||
// Constructor initializers.
|
||||
@ -1554,7 +1551,7 @@ DEF_TRAVERSE_DECL(ImplicitParamDecl, {
|
||||
|
||||
DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
|
||||
// A non-type template parameter, e.g. "S" in template<int S> class Foo ...
|
||||
TRY_TO(TraverseVarHelper(D));
|
||||
TRY_TO(TraverseDeclaratorHelper(D));
|
||||
TRY_TO(TraverseStmt(D->getDefaultArgument()));
|
||||
})
|
||||
|
||||
@ -1577,12 +1574,11 @@ DEF_TRAVERSE_DECL(ParmVarDecl, {
|
||||
// ----------------- Stmt traversal -----------------
|
||||
//
|
||||
// For stmts, we automate (in the DEF_TRAVERSE_STMT macro) iterating
|
||||
// over the children defined in child_begin/child_end (every stmt
|
||||
// defines these, though sometimes the range is empty). Each
|
||||
// individual Traverse* method only needs to worry about children
|
||||
// other than those. To see what child_begin()/end() does for a given
|
||||
// class, see, e.g.,
|
||||
// http://clang.llvm.org/doxygen/Stmt_8cpp_source.html
|
||||
// over the children defined in children() (every stmt defines these,
|
||||
// though sometimes the range is empty). Each individual Traverse*
|
||||
// method only needs to worry about children other than those. To see
|
||||
// what children() does for a given class, see, e.g.,
|
||||
// http://clang.llvm.org/doxygen/Stmt_8cpp_source.html
|
||||
|
||||
// This macro makes available a variable S, the passed-in stmt.
|
||||
#define DEF_TRAVERSE_STMT(STMT, CODE) \
|
||||
@ -1590,9 +1586,8 @@ template<typename Derived> \
|
||||
bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) { \
|
||||
TRY_TO(WalkUpFrom##STMT(S)); \
|
||||
{ CODE; } \
|
||||
for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); \
|
||||
C != CEnd; ++C) { \
|
||||
TRY_TO(TraverseStmt(*C)); \
|
||||
for (Stmt::child_range range = S->children(); range; ++range) { \
|
||||
TRY_TO(TraverseStmt(*range)); \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
@ -1608,12 +1603,12 @@ DEF_TRAVERSE_STMT(AsmStmt, {
|
||||
for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
|
||||
TRY_TO(TraverseStmt(S->getClobber(I)));
|
||||
}
|
||||
// child_begin()/end() iterates over inputExpr and outputExpr.
|
||||
// children() iterates over inputExpr and outputExpr.
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXCatchStmt, {
|
||||
TRY_TO(TraverseDecl(S->getExceptionDecl()));
|
||||
// child_begin()/end() iterates over the handler block.
|
||||
// children() iterates over the handler block.
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(DeclStmt, {
|
||||
@ -1621,11 +1616,11 @@ DEF_TRAVERSE_STMT(DeclStmt, {
|
||||
I != E; ++I) {
|
||||
TRY_TO(TraverseDecl(*I));
|
||||
}
|
||||
// Suppress the default iteration over child_begin/end by
|
||||
// Suppress the default iteration over children() by
|
||||
// returning. Here's why: A DeclStmt looks like 'type var [=
|
||||
// initializer]'. The decls above already traverse over the
|
||||
// initializers, so we don't have to do it again (which
|
||||
// child_begin/end would do).
|
||||
// children() would do).
|
||||
return true;
|
||||
})
|
||||
|
||||
@ -1652,17 +1647,16 @@ DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
|
||||
DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
|
||||
DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
|
||||
DEF_TRAVERSE_STMT(ReturnStmt, { })
|
||||
DEF_TRAVERSE_STMT(SwitchCase, { })
|
||||
DEF_TRAVERSE_STMT(SwitchStmt, { })
|
||||
DEF_TRAVERSE_STMT(WhileStmt, { })
|
||||
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
|
||||
if (S->hasExplicitTemplateArgs()) {
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(
|
||||
S->getTemplateArgs(), S->getNumTemplateArgs()));
|
||||
}
|
||||
TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(DeclRefExpr, {
|
||||
@ -1695,27 +1689,27 @@ DEF_TRAVERSE_STMT(ImplicitCastExpr, {
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CStyleCastExpr, {
|
||||
TRY_TO(TraverseType(S->getTypeAsWritten()));
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXFunctionalCastExpr, {
|
||||
TRY_TO(TraverseType(S->getTypeAsWritten()));
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXConstCastExpr, {
|
||||
TRY_TO(TraverseType(S->getTypeAsWritten()));
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXDynamicCastExpr, {
|
||||
TRY_TO(TraverseType(S->getTypeAsWritten()));
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXReinterpretCastExpr, {
|
||||
TRY_TO(TraverseType(S->getTypeAsWritten()));
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXStaticCastExpr, {
|
||||
TRY_TO(TraverseType(S->getTypeAsWritten()));
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
|
||||
})
|
||||
|
||||
// InitListExpr is a tricky one, because we want to do all our work on
|
||||
@ -1729,9 +1723,8 @@ bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) {
|
||||
S = Syn;
|
||||
TRY_TO(WalkUpFromInitListExpr(S));
|
||||
// All we need are the default actions. FIXME: use a helper function.
|
||||
for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end();
|
||||
C != CEnd; ++C) {
|
||||
TRY_TO(TraverseStmt(*C));
|
||||
for (Stmt::child_range range = S->children(); range; ++range) {
|
||||
TRY_TO(TraverseStmt(*range));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1739,12 +1732,12 @@ bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) {
|
||||
DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
|
||||
// This is called for code like 'return T()' where T is a built-in
|
||||
// (i.e. non-class) type.
|
||||
if (!S->isImplicit())
|
||||
TRY_TO(TraverseType(S->getType()));
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXNewExpr, {
|
||||
TRY_TO(TraverseType(S->getAllocatedType()));
|
||||
// The child-iterator will pick up the other arguments.
|
||||
TRY_TO(TraverseTypeLoc(S->getAllocatedTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(OffsetOfExpr, {
|
||||
@ -1769,15 +1762,43 @@ DEF_TRAVERSE_STMT(CXXTypeidExpr, {
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(TypesCompatibleExpr, {
|
||||
TRY_TO(TraverseTypeLoc(S->getArgTInfo1()->getTypeLoc()));
|
||||
TRY_TO(TraverseTypeLoc(S->getArgTInfo2()->getTypeLoc()));
|
||||
DEF_TRAVERSE_STMT(CXXUuidofExpr, {
|
||||
// The child-iterator will pick up the arg if it's an expression,
|
||||
// but not if it's a type.
|
||||
if (S->isTypeOperand())
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(UnaryTypeTraitExpr, {
|
||||
TRY_TO(TraverseType(S->getQueriedType()));
|
||||
TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(BinaryTypeTraitExpr, {
|
||||
TRY_TO(TraverseTypeLoc(S->getLhsTypeSourceInfo()->getTypeLoc()));
|
||||
TRY_TO(TraverseTypeLoc(S->getRhsTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(VAArgExpr, {
|
||||
// The child-iterator will pick up the expression argument.
|
||||
TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
|
||||
// This is called for code like 'return T()' where T is a class type.
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
|
||||
// This is called for code like 'T()', where T is a template argument.
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
// These expressions all might take explicit template arguments.
|
||||
// We traverse those if so. FIXME: implement these.
|
||||
DEF_TRAVERSE_STMT(CXXConstructExpr, { })
|
||||
DEF_TRAVERSE_STMT(CallExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXMemberCallExpr, { })
|
||||
|
||||
// These exprs (most of them), do not need any action except iterating
|
||||
// over the children.
|
||||
DEF_TRAVERSE_STMT(AddrLabelExpr, { })
|
||||
@ -1790,53 +1811,64 @@ DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXExprWithTemporaries, { })
|
||||
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
|
||||
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
|
||||
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
|
||||
TRY_TO(TraverseTypeLoc(ScopeInfo->getTypeLoc()));
|
||||
if (TypeSourceInfo *DestroyedTypeInfo = S->getDestroyedTypeInfo())
|
||||
TRY_TO(TraverseTypeLoc(DestroyedTypeInfo->getTypeLoc()));
|
||||
})
|
||||
DEF_TRAVERSE_STMT(CXXThisExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXThrowExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, { })
|
||||
DEF_TRAVERSE_STMT(DesignatedInitExpr, { })
|
||||
DEF_TRAVERSE_STMT(ExtVectorElementExpr, { })
|
||||
DEF_TRAVERSE_STMT(GNUNullExpr, { })
|
||||
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCEncodeExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCImplicitSetterGetterRefExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCIsaExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCMessageExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCProtocolExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCSelectorExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCSuperExpr, { })
|
||||
DEF_TRAVERSE_STMT(ParenExpr, { })
|
||||
DEF_TRAVERSE_STMT(ParenListExpr, { })
|
||||
DEF_TRAVERSE_STMT(PredefinedExpr, { })
|
||||
DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
|
||||
DEF_TRAVERSE_STMT(StmtExpr, { })
|
||||
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, { })
|
||||
DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { })
|
||||
DEF_TRAVERSE_STMT(VAArgExpr, {
|
||||
// The child-iterator will pick up the expression argument.
|
||||
TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc()));
|
||||
})
|
||||
DEF_TRAVERSE_STMT(CXXConstructExpr, { })
|
||||
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
|
||||
if (S->hasExplicitTemplateArgs()) {
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
|
||||
S->getNumTemplateArgs()));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
|
||||
if (S->hasExplicitTemplateArgs()) {
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
|
||||
S->getNumTemplateArgs()));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
|
||||
// This is called for code like 'return T()' where T is a class type.
|
||||
TRY_TO(TraverseType(S->getType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CallExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXMemberCallExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
|
||||
DEF_TRAVERSE_STMT(OpaqueValueExpr, { })
|
||||
DEF_TRAVERSE_STMT(CUDAKernelCallExpr, { })
|
||||
|
||||
// These operators (all of them) do not need any action except
|
||||
// iterating over the children.
|
||||
DEF_TRAVERSE_STMT(BinaryConditionalOperator, { })
|
||||
DEF_TRAVERSE_STMT(ConditionalOperator, { })
|
||||
DEF_TRAVERSE_STMT(UnaryOperator, { })
|
||||
DEF_TRAVERSE_STMT(BinaryOperator, { })
|
||||
DEF_TRAVERSE_STMT(CompoundAssignOperator, { })
|
||||
DEF_TRAVERSE_STMT(CXXNoexceptExpr, { })
|
||||
DEF_TRAVERSE_STMT(PackExpansionExpr, { })
|
||||
DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
|
||||
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
|
||||
|
||||
// These literals (all of them) do not need any action.
|
||||
DEF_TRAVERSE_STMT(IntegerLiteral, { })
|
||||
@ -1861,7 +1893,6 @@ DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
|
||||
// http://clang.llvm.org/doxygen/classclang_1_1CXXTypeidExpr.html
|
||||
// http://clang.llvm.org/doxygen/classclang_1_1SizeOfAlignOfExpr.html
|
||||
// http://clang.llvm.org/doxygen/classclang_1_1TypesCompatibleExpr.html
|
||||
// http://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html
|
||||
// Every class that has getQualifier.
|
||||
|
||||
#undef DEF_TRAVERSE_STMT
|
||||
|
@ -109,25 +109,7 @@ class Redeclarable {
|
||||
|
||||
/// \brief Set the previous declaration. If PrevDecl is NULL, set this as the
|
||||
/// first and only declaration.
|
||||
void setPreviousDeclaration(decl_type *PrevDecl) {
|
||||
decl_type *First;
|
||||
|
||||
if (PrevDecl) {
|
||||
// Point to previous. Make sure that this is actually the most recent
|
||||
// redeclaration, or we can build invalid chains. If the most recent
|
||||
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
|
||||
RedeclLink = PreviousDeclLink(llvm::cast<decl_type>(
|
||||
PrevDecl->getMostRecentDeclaration()));
|
||||
First = PrevDecl->getFirstDeclaration();
|
||||
assert(First->RedeclLink.NextIsLatest() && "Expected first");
|
||||
} else {
|
||||
// Make this first.
|
||||
First = static_cast<decl_type*>(this);
|
||||
}
|
||||
|
||||
// First one will point to this one as latest.
|
||||
First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
|
||||
}
|
||||
void setPreviousDeclaration(decl_type *PrevDecl);
|
||||
|
||||
/// \brief Iterates through all the redeclarations of the same decl.
|
||||
class redecl_iterator {
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/StmtIterator.h"
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
#include "clang/AST/FullExpr.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include <string>
|
||||
@ -104,13 +103,7 @@ class Stmt {
|
||||
first##BASE##Constant=FIRST##Class, last##BASE##Constant=LAST##Class
|
||||
#define ABSTRACT_STMT(STMT)
|
||||
#include "clang/AST/StmtNodes.inc"
|
||||
};
|
||||
private:
|
||||
/// \brief The statement class.
|
||||
const unsigned sClass : 8;
|
||||
|
||||
/// \brief The reference count for this statement.
|
||||
unsigned RefCount : 24;
|
||||
};
|
||||
|
||||
// Make vanilla 'new' and 'delete' illegal for Stmts.
|
||||
protected:
|
||||
@ -122,6 +115,77 @@ class Stmt {
|
||||
assert(0 && "Stmts cannot be released with regular 'delete'.");
|
||||
}
|
||||
|
||||
class StmtBitfields {
|
||||
friend class Stmt;
|
||||
|
||||
/// \brief The statement class.
|
||||
unsigned sClass : 8;
|
||||
};
|
||||
enum { NumStmtBits = 8 };
|
||||
|
||||
class CompoundStmtBitfields {
|
||||
friend class CompoundStmt;
|
||||
unsigned : NumStmtBits;
|
||||
|
||||
unsigned NumStmts : 32 - NumStmtBits;
|
||||
};
|
||||
|
||||
class ExprBitfields {
|
||||
friend class Expr;
|
||||
friend class DeclRefExpr; // computeDependence
|
||||
friend class InitListExpr; // ctor
|
||||
friend class DesignatedInitExpr; // ctor
|
||||
friend class BlockDeclRefExpr; // ctor
|
||||
friend class ASTStmtReader; // deserialization
|
||||
friend class CXXNewExpr; // ctor
|
||||
friend class DependentScopeDeclRefExpr; // ctor
|
||||
friend class CXXConstructExpr; // ctor
|
||||
friend class CallExpr; // ctor
|
||||
friend class OffsetOfExpr; // ctor
|
||||
friend class ObjCMessageExpr; // ctor
|
||||
friend class ShuffleVectorExpr; // ctor
|
||||
friend class ParenListExpr; // ctor
|
||||
friend class CXXUnresolvedConstructExpr; // ctor
|
||||
friend class CXXDependentScopeMemberExpr; // ctor
|
||||
friend class OverloadExpr; // ctor
|
||||
unsigned : NumStmtBits;
|
||||
|
||||
unsigned ValueKind : 2;
|
||||
unsigned ObjectKind : 2;
|
||||
unsigned TypeDependent : 1;
|
||||
unsigned ValueDependent : 1;
|
||||
unsigned ContainsUnexpandedParameterPack : 1;
|
||||
};
|
||||
enum { NumExprBits = 15 };
|
||||
|
||||
class CastExprBitfields {
|
||||
friend class CastExpr;
|
||||
unsigned : NumExprBits;
|
||||
|
||||
unsigned Kind : 6;
|
||||
unsigned BasePathSize : 32 - 6 - NumExprBits;
|
||||
};
|
||||
|
||||
class CallExprBitfields {
|
||||
friend class CallExpr;
|
||||
unsigned : NumExprBits;
|
||||
|
||||
unsigned NumPreArgs : 1;
|
||||
};
|
||||
|
||||
union {
|
||||
// FIXME: this is wasteful on 64-bit platforms.
|
||||
void *Aligner;
|
||||
|
||||
StmtBitfields StmtBits;
|
||||
CompoundStmtBitfields CompoundStmtBits;
|
||||
ExprBitfields ExprBits;
|
||||
CastExprBitfields CastExprBits;
|
||||
CallExprBitfields CallExprBits;
|
||||
};
|
||||
|
||||
friend class ASTStmtReader;
|
||||
|
||||
public:
|
||||
// Only allow allocation of Stmts using the allocator in ASTContext
|
||||
// or by doing a placement new.
|
||||
@ -152,44 +216,27 @@ class Stmt {
|
||||
|
||||
protected:
|
||||
/// \brief Construct an empty statement.
|
||||
explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC), RefCount(1) {
|
||||
explicit Stmt(StmtClass SC, EmptyShell) {
|
||||
StmtBits.sClass = SC;
|
||||
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
|
||||
}
|
||||
|
||||
public:
|
||||
Stmt(StmtClass SC) : sClass(SC), RefCount(1) {
|
||||
Stmt(StmtClass SC) {
|
||||
StmtBits.sClass = SC;
|
||||
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
|
||||
}
|
||||
virtual ~Stmt() {}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// \brief True if this statement's refcount is in a valid state.
|
||||
/// Should be used only in assertions.
|
||||
bool isRetained() const {
|
||||
return (RefCount >= 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \brief Increases the reference count for this statement.
|
||||
///
|
||||
/// Invoke the Retain() operation when this statement or expression
|
||||
/// is being shared by another owner.
|
||||
Stmt *Retain() {
|
||||
assert(RefCount >= 1);
|
||||
++RefCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
StmtClass getStmtClass() const {
|
||||
assert(RefCount >= 1 && "Referencing already-destroyed statement!");
|
||||
return (StmtClass)sClass;
|
||||
return static_cast<StmtClass>(StmtBits.sClass);
|
||||
}
|
||||
const char *getStmtClassName() const;
|
||||
|
||||
/// SourceLocation tokens are not useful in isolation - they are low level
|
||||
/// value objects created/interpreted by SourceManager. We assume AST
|
||||
/// clients will have a pointer to the respective SourceManager.
|
||||
virtual SourceRange getSourceRange() const = 0;
|
||||
SourceRange getSourceRange() const;
|
||||
|
||||
SourceLocation getLocStart() const { return getSourceRange().getBegin(); }
|
||||
SourceLocation getLocEnd() const { return getSourceRange().getEnd(); }
|
||||
|
||||
@ -236,22 +283,25 @@ class Stmt {
|
||||
/// within CFGs.
|
||||
bool hasImplicitControlFlow() const;
|
||||
|
||||
/// Child Iterators: All subclasses must implement child_begin and child_end
|
||||
/// to permit easy iteration over the substatements/subexpessions of an
|
||||
/// AST node. This permits easy iteration over all nodes in the AST.
|
||||
/// Child Iterators: All subclasses must implement 'children'
|
||||
/// to permit easy iteration over the substatements/subexpessions of an
|
||||
/// AST node. This permits easy iteration over all nodes in the AST.
|
||||
typedef StmtIterator child_iterator;
|
||||
typedef ConstStmtIterator const_child_iterator;
|
||||
|
||||
virtual child_iterator child_begin() = 0;
|
||||
virtual child_iterator child_end() = 0;
|
||||
typedef StmtRange child_range;
|
||||
typedef ConstStmtRange const_child_range;
|
||||
|
||||
const_child_iterator child_begin() const {
|
||||
return const_child_iterator(const_cast<Stmt*>(this)->child_begin());
|
||||
child_range children();
|
||||
const_child_range children() const {
|
||||
return const_cast<Stmt*>(this)->children();
|
||||
}
|
||||
|
||||
const_child_iterator child_end() const {
|
||||
return const_child_iterator(const_cast<Stmt*>(this)->child_end());
|
||||
}
|
||||
child_iterator child_begin() { return children().first; }
|
||||
child_iterator child_end() { return children().second; }
|
||||
|
||||
const_child_iterator child_begin() const { return children().first; }
|
||||
const_child_iterator child_end() const { return children().second; }
|
||||
|
||||
/// \brief Produce a unique representation of the given statement.
|
||||
///
|
||||
@ -265,7 +315,7 @@ class Stmt {
|
||||
/// parameters are identified by index/level rather than their
|
||||
/// declaration pointers) or the exact representation of the statement as
|
||||
/// written in the source.
|
||||
void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
|
||||
bool Canonical);
|
||||
};
|
||||
|
||||
@ -314,8 +364,10 @@ class DeclStmt : public Stmt {
|
||||
static bool classof(const DeclStmt *) { return true; }
|
||||
|
||||
// Iterators over subexpressions.
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(child_iterator(DG.begin(), DG.end()),
|
||||
child_iterator(DG.end(), DG.end()));
|
||||
}
|
||||
|
||||
typedef DeclGroupRef::iterator decl_iterator;
|
||||
typedef DeclGroupRef::const_iterator const_decl_iterator;
|
||||
@ -330,8 +382,16 @@ class DeclStmt : public Stmt {
|
||||
///
|
||||
class NullStmt : public Stmt {
|
||||
SourceLocation SemiLoc;
|
||||
|
||||
/// \brief Whether the null statement was preceded by an empty macro, e.g:
|
||||
/// @code
|
||||
/// #define CALL(x)
|
||||
/// CALL(0);
|
||||
/// @endcode
|
||||
bool LeadingEmptyMacro;
|
||||
public:
|
||||
NullStmt(SourceLocation L) : Stmt(NullStmtClass), SemiLoc(L) {}
|
||||
NullStmt(SourceLocation L, bool LeadingEmptyMacro = false)
|
||||
: Stmt(NullStmtClass), SemiLoc(L), LeadingEmptyMacro(LeadingEmptyMacro) {}
|
||||
|
||||
/// \brief Build an empty null statement.
|
||||
explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { }
|
||||
@ -339,55 +399,66 @@ class NullStmt : public Stmt {
|
||||
SourceLocation getSemiLoc() const { return SemiLoc; }
|
||||
void setSemiLoc(SourceLocation L) { SemiLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
|
||||
bool hasLeadingEmptyMacro() const { return LeadingEmptyMacro; }
|
||||
|
||||
SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == NullStmtClass;
|
||||
}
|
||||
static bool classof(const NullStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(); }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
};
|
||||
|
||||
/// CompoundStmt - This represents a group of statements like { stmt stmt }.
|
||||
///
|
||||
class CompoundStmt : public Stmt {
|
||||
Stmt** Body;
|
||||
unsigned NumStmts;
|
||||
SourceLocation LBracLoc, RBracLoc;
|
||||
public:
|
||||
CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned numStmts,
|
||||
SourceLocation LB, SourceLocation RB)
|
||||
: Stmt(CompoundStmtClass), NumStmts(numStmts), LBracLoc(LB), RBracLoc(RB) {
|
||||
CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned NumStmts,
|
||||
SourceLocation LB, SourceLocation RB)
|
||||
: Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) {
|
||||
CompoundStmtBits.NumStmts = NumStmts;
|
||||
|
||||
if (NumStmts == 0) {
|
||||
Body = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Body = new (C) Stmt*[NumStmts];
|
||||
memcpy(Body, StmtStart, numStmts * sizeof(*Body));
|
||||
memcpy(Body, StmtStart, NumStmts * sizeof(*Body));
|
||||
}
|
||||
|
||||
// \brief Build an empty compound statement.
|
||||
explicit CompoundStmt(EmptyShell Empty)
|
||||
: Stmt(CompoundStmtClass, Empty), Body(0), NumStmts(0) { }
|
||||
: Stmt(CompoundStmtClass, Empty), Body(0) {
|
||||
CompoundStmtBits.NumStmts = 0;
|
||||
}
|
||||
|
||||
void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts);
|
||||
|
||||
bool body_empty() const { return NumStmts == 0; }
|
||||
unsigned size() const { return NumStmts; }
|
||||
bool body_empty() const { return CompoundStmtBits.NumStmts == 0; }
|
||||
unsigned size() const { return CompoundStmtBits.NumStmts; }
|
||||
|
||||
typedef Stmt** body_iterator;
|
||||
body_iterator body_begin() { return Body; }
|
||||
body_iterator body_end() { return Body + NumStmts; }
|
||||
Stmt *body_back() { return NumStmts ? Body[NumStmts-1] : 0; }
|
||||
body_iterator body_end() { return Body + size(); }
|
||||
Stmt *body_back() { return !body_empty() ? Body[size()-1] : 0; }
|
||||
|
||||
void setLastStmt(Stmt *S) {
|
||||
assert(!body_empty() && "setLastStmt");
|
||||
Body[size()-1] = S;
|
||||
}
|
||||
|
||||
typedef Stmt* const * const_body_iterator;
|
||||
const_body_iterator body_begin() const { return Body; }
|
||||
const_body_iterator body_end() const { return Body + NumStmts; }
|
||||
const Stmt *body_back() const { return NumStmts ? Body[NumStmts-1] : 0; }
|
||||
const_body_iterator body_end() const { return Body + size(); }
|
||||
const Stmt *body_back() const { return !body_empty() ? Body[size()-1] : 0; }
|
||||
|
||||
typedef std::reverse_iterator<body_iterator> reverse_body_iterator;
|
||||
reverse_body_iterator body_rbegin() {
|
||||
@ -408,7 +479,7 @@ class CompoundStmt : public Stmt {
|
||||
return const_reverse_body_iterator(body_begin());
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(LBracLoc, RBracLoc);
|
||||
}
|
||||
|
||||
@ -423,8 +494,9 @@ class CompoundStmt : public Stmt {
|
||||
static bool classof(const CompoundStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts);
|
||||
}
|
||||
};
|
||||
|
||||
// SwitchCase is the base class for CaseStmt and DefaultStmt,
|
||||
@ -443,17 +515,15 @@ class SwitchCase : public Stmt {
|
||||
|
||||
void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; }
|
||||
|
||||
Stmt *getSubStmt() { return v_getSubStmt(); }
|
||||
Stmt *getSubStmt();
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(); }
|
||||
SourceRange getSourceRange() const { return SourceRange(); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CaseStmtClass ||
|
||||
T->getStmtClass() == DefaultStmtClass;
|
||||
T->getStmtClass() == DefaultStmtClass;
|
||||
}
|
||||
static bool classof(const SwitchCase *) { return true; }
|
||||
protected:
|
||||
virtual Stmt* v_getSubStmt() = 0;
|
||||
};
|
||||
|
||||
class CaseStmt : public SwitchCase {
|
||||
@ -463,8 +533,6 @@ class CaseStmt : public SwitchCase {
|
||||
SourceLocation CaseLoc;
|
||||
SourceLocation EllipsisLoc;
|
||||
SourceLocation ColonLoc;
|
||||
|
||||
virtual Stmt* v_getSubStmt() { return getSubStmt(); }
|
||||
public:
|
||||
CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc,
|
||||
SourceLocation ellipsisLoc, SourceLocation colonLoc)
|
||||
@ -504,7 +572,7 @@ class CaseStmt : public SwitchCase {
|
||||
void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); }
|
||||
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
// Handle deeply nested case statements with iteration instead of recursion.
|
||||
const CaseStmt *CS = this;
|
||||
while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt()))
|
||||
@ -518,15 +586,15 @@ class CaseStmt : public SwitchCase {
|
||||
static bool classof(const CaseStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[END_EXPR]);
|
||||
}
|
||||
};
|
||||
|
||||
class DefaultStmt : public SwitchCase {
|
||||
Stmt* SubStmt;
|
||||
SourceLocation DefaultLoc;
|
||||
SourceLocation ColonLoc;
|
||||
virtual Stmt* v_getSubStmt() { return getSubStmt(); }
|
||||
public:
|
||||
DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) :
|
||||
SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL),
|
||||
@ -544,7 +612,7 @@ class DefaultStmt : public SwitchCase {
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
void setColonLoc(SourceLocation L) { ColonLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(DefaultLoc, SubStmt->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
@ -553,42 +621,43 @@ class DefaultStmt : public SwitchCase {
|
||||
static bool classof(const DefaultStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
|
||||
};
|
||||
|
||||
|
||||
/// LabelStmt - Represents a label, which has a substatement. For example:
|
||||
/// foo: return;
|
||||
///
|
||||
class LabelStmt : public Stmt {
|
||||
IdentifierInfo *Label;
|
||||
LabelDecl *TheDecl;
|
||||
Stmt *SubStmt;
|
||||
SourceLocation IdentLoc;
|
||||
public:
|
||||
LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt)
|
||||
: Stmt(LabelStmtClass), Label(label),
|
||||
SubStmt(substmt), IdentLoc(IL) {}
|
||||
LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt)
|
||||
: Stmt(LabelStmtClass), TheDecl(D), SubStmt(substmt), IdentLoc(IL) {
|
||||
}
|
||||
|
||||
// \brief Build an empty label statement.
|
||||
explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { }
|
||||
|
||||
SourceLocation getIdentLoc() const { return IdentLoc; }
|
||||
IdentifierInfo *getID() const { return Label; }
|
||||
void setID(IdentifierInfo *II) { Label = II; }
|
||||
LabelDecl *getDecl() const { return TheDecl; }
|
||||
void setDecl(LabelDecl *D) { TheDecl = D; }
|
||||
const char *getName() const;
|
||||
Stmt *getSubStmt() { return SubStmt; }
|
||||
const Stmt *getSubStmt() const { return SubStmt; }
|
||||
void setIdentLoc(SourceLocation L) { IdentLoc = L; }
|
||||
void setSubStmt(Stmt *SS) { SubStmt = SS; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(IdentLoc, SubStmt->getLocEnd());
|
||||
}
|
||||
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == LabelStmtClass;
|
||||
}
|
||||
static bool classof(const LabelStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
|
||||
@ -635,22 +704,23 @@ class IfStmt : public Stmt {
|
||||
SourceLocation getElseLoc() const { return ElseLoc; }
|
||||
void setElseLoc(SourceLocation L) { ElseLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
if (SubExprs[ELSE])
|
||||
return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd());
|
||||
else
|
||||
return SourceRange(IfLoc, SubExprs[THEN]->getLocEnd());
|
||||
}
|
||||
|
||||
// Iterators over subexpressions. The iterators will include iterating
|
||||
// over the initialization expression referenced by the condition variable.
|
||||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == IfStmtClass;
|
||||
}
|
||||
static bool classof(const IfStmt *) { return true; }
|
||||
|
||||
// Iterators over subexpressions. The iterators will include iterating
|
||||
// over the initialization expression referenced by the condition variable.
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// SwitchStmt - This represents a 'switch' stmt.
|
||||
@ -662,6 +732,11 @@ class SwitchStmt : public Stmt {
|
||||
SwitchCase *FirstCase;
|
||||
SourceLocation SwitchLoc;
|
||||
|
||||
/// If the SwitchStmt is a switch on an enum value, this records whether
|
||||
/// all the enum values were covered by CaseStmts. This value is meant to
|
||||
/// be a hint for possible clients.
|
||||
unsigned AllEnumCasesCovered : 1;
|
||||
|
||||
public:
|
||||
SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond);
|
||||
|
||||
@ -705,21 +780,34 @@ class SwitchStmt : public Stmt {
|
||||
}
|
||||
void addSwitchCase(SwitchCase *SC) {
|
||||
assert(!SC->getNextSwitchCase() && "case/default already added to a switch");
|
||||
SC->Retain();
|
||||
SC->setNextSwitchCase(FirstCase);
|
||||
FirstCase = SC;
|
||||
}
|
||||
virtual SourceRange getSourceRange() const {
|
||||
|
||||
/// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a
|
||||
/// switch over an enum value then all cases have been explicitly covered.
|
||||
void setAllEnumCasesCovered() {
|
||||
AllEnumCasesCovered = 1;
|
||||
}
|
||||
|
||||
/// Returns true if the SwitchStmt is a switch of an enum value and all cases
|
||||
/// have been explicitly covered.
|
||||
bool isAllEnumCasesCovered() const {
|
||||
return (bool) AllEnumCasesCovered;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
// Iterators
|
||||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == SwitchStmtClass;
|
||||
}
|
||||
static bool classof(const SwitchStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
|
||||
@ -757,7 +845,7 @@ class WhileStmt : public Stmt {
|
||||
SourceLocation getWhileLoc() const { return WhileLoc; }
|
||||
void setWhileLoc(SourceLocation L) { WhileLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
@ -766,14 +854,15 @@ class WhileStmt : public Stmt {
|
||||
static bool classof(const WhileStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
};
|
||||
|
||||
/// DoStmt - This represents a 'do/while' stmt.
|
||||
///
|
||||
class DoStmt : public Stmt {
|
||||
enum { COND, BODY, END_EXPR };
|
||||
enum { BODY, COND, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR];
|
||||
SourceLocation DoLoc;
|
||||
SourceLocation WhileLoc;
|
||||
@ -805,7 +894,7 @@ class DoStmt : public Stmt {
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(DoLoc, RParenLoc);
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
@ -814,8 +903,9 @@ class DoStmt : public Stmt {
|
||||
static bool classof(const DoStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -870,7 +960,7 @@ class ForStmt : public Stmt {
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
@ -879,32 +969,33 @@ class ForStmt : public Stmt {
|
||||
static bool classof(const ForStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
};
|
||||
|
||||
/// GotoStmt - This represents a direct goto.
|
||||
///
|
||||
class GotoStmt : public Stmt {
|
||||
LabelStmt *Label;
|
||||
LabelDecl *Label;
|
||||
SourceLocation GotoLoc;
|
||||
SourceLocation LabelLoc;
|
||||
public:
|
||||
GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL)
|
||||
GotoStmt(LabelDecl *label, SourceLocation GL, SourceLocation LL)
|
||||
: Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {}
|
||||
|
||||
/// \brief Build an empty goto statement.
|
||||
explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { }
|
||||
|
||||
LabelStmt *getLabel() const { return Label; }
|
||||
void setLabel(LabelStmt *S) { Label = S; }
|
||||
LabelDecl *getLabel() const { return Label; }
|
||||
void setLabel(LabelDecl *D) { Label = D; }
|
||||
|
||||
SourceLocation getGotoLoc() const { return GotoLoc; }
|
||||
void setGotoLoc(SourceLocation L) { GotoLoc = L; }
|
||||
SourceLocation getLabelLoc() const { return LabelLoc; }
|
||||
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(GotoLoc, LabelLoc);
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
@ -913,8 +1004,7 @@ class GotoStmt : public Stmt {
|
||||
static bool classof(const GotoStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// IndirectGotoStmt - This represents an indirect goto.
|
||||
@ -938,11 +1028,18 @@ class IndirectGotoStmt : public Stmt {
|
||||
void setStarLoc(SourceLocation L) { StarLoc = L; }
|
||||
SourceLocation getStarLoc() const { return StarLoc; }
|
||||
|
||||
Expr *getTarget();
|
||||
const Expr *getTarget() const;
|
||||
Expr *getTarget() { return reinterpret_cast<Expr*>(Target); }
|
||||
const Expr *getTarget() const {return reinterpret_cast<const Expr*>(Target);}
|
||||
void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
/// getConstantTarget - Returns the fixed target of this indirect
|
||||
/// goto, if one exists.
|
||||
LabelDecl *getConstantTarget();
|
||||
const LabelDecl *getConstantTarget() const {
|
||||
return const_cast<IndirectGotoStmt*>(this)->getConstantTarget();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(GotoLoc, Target->getLocEnd());
|
||||
}
|
||||
|
||||
@ -952,8 +1049,7 @@ class IndirectGotoStmt : public Stmt {
|
||||
static bool classof(const IndirectGotoStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(&Target, &Target+1); }
|
||||
};
|
||||
|
||||
|
||||
@ -970,7 +1066,7 @@ class ContinueStmt : public Stmt {
|
||||
SourceLocation getContinueLoc() const { return ContinueLoc; }
|
||||
void setContinueLoc(SourceLocation L) { ContinueLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(ContinueLoc);
|
||||
}
|
||||
|
||||
@ -980,8 +1076,7 @@ class ContinueStmt : public Stmt {
|
||||
static bool classof(const ContinueStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// BreakStmt - This represents a break.
|
||||
@ -997,7 +1092,7 @@ class BreakStmt : public Stmt {
|
||||
SourceLocation getBreakLoc() const { return BreakLoc; }
|
||||
void setBreakLoc(SourceLocation L) { BreakLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(BreakLoc); }
|
||||
SourceRange getSourceRange() const { return SourceRange(BreakLoc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BreakStmtClass;
|
||||
@ -1005,8 +1100,7 @@ class BreakStmt : public Stmt {
|
||||
static bool classof(const BreakStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
|
||||
@ -1050,7 +1144,7 @@ class ReturnStmt : public Stmt {
|
||||
const VarDecl *getNRVOCandidate() const { return NRVOCandidate; }
|
||||
void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; }
|
||||
|
||||
virtual SourceRange getSourceRange() const;
|
||||
SourceRange getSourceRange() const;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ReturnStmtClass;
|
||||
@ -1058,8 +1152,10 @@ class ReturnStmt : public Stmt {
|
||||
static bool classof(const ReturnStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
if (RetExpr) return child_range(&RetExpr, &RetExpr+1);
|
||||
return child_range();
|
||||
}
|
||||
};
|
||||
|
||||
/// AsmStmt - This represents a GNU inline-assembly statement extension.
|
||||
@ -1257,7 +1353,7 @@ class AsmStmt : public Stmt {
|
||||
StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
|
||||
const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(AsmLoc, RParenLoc);
|
||||
}
|
||||
|
||||
@ -1304,10 +1400,9 @@ class AsmStmt : public Stmt {
|
||||
return &Exprs[0] + NumOutputs;
|
||||
}
|
||||
|
||||
// Child iterators
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -37,7 +37,7 @@ class CXXCatchStmt : public Stmt {
|
||||
CXXCatchStmt(EmptyShell Empty)
|
||||
: Stmt(CXXCatchStmtClass), ExceptionDecl(0), HandlerBlock(0) {}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(CatchLoc, HandlerBlock->getLocEnd());
|
||||
}
|
||||
|
||||
@ -51,8 +51,7 @@ class CXXCatchStmt : public Stmt {
|
||||
}
|
||||
static bool classof(const CXXCatchStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(&HandlerBlock, &HandlerBlock+1); }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
@ -84,7 +83,7 @@ class CXXTryStmt : public Stmt {
|
||||
static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty,
|
||||
unsigned numHandlers);
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getTryLoc(), getEndLoc());
|
||||
}
|
||||
|
||||
@ -113,8 +112,9 @@ class CXXTryStmt : public Stmt {
|
||||
}
|
||||
static bool classof(const CXXTryStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(getStmts(), getStmts() + getNumHandlers() + 1);
|
||||
}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===--- StmtIterator.h - Iterators for Statements ------------------------===//
|
||||
//===--- StmtIterator.h - Iterators for Statements --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -14,7 +14,7 @@
|
||||
#ifndef LLVM_CLANG_AST_STMT_ITR_H
|
||||
#define LLVM_CLANG_AST_STMT_ITR_H
|
||||
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
@ -51,11 +51,11 @@ class StmtIteratorBase {
|
||||
return (RawVAPtr & Flags) == 0;
|
||||
}
|
||||
|
||||
VariableArrayType* getVAPtr() const {
|
||||
return reinterpret_cast<VariableArrayType*>(RawVAPtr & ~Flags);
|
||||
const VariableArrayType *getVAPtr() const {
|
||||
return reinterpret_cast<const VariableArrayType*>(RawVAPtr & ~Flags);
|
||||
}
|
||||
|
||||
void setVAPtr(VariableArrayType* P) {
|
||||
void setVAPtr(const VariableArrayType *P) {
|
||||
assert (inDecl() || inDeclGroup() || inSizeOfTypeVA());
|
||||
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
|
||||
}
|
||||
@ -68,7 +68,7 @@ class StmtIteratorBase {
|
||||
|
||||
StmtIteratorBase(Stmt **s) : stmt(s), decl(0), RawVAPtr(0) {}
|
||||
StmtIteratorBase(Decl *d, Stmt **s);
|
||||
StmtIteratorBase(VariableArrayType *t);
|
||||
StmtIteratorBase(const VariableArrayType *t);
|
||||
StmtIteratorBase(Decl **dgi, Decl **dge);
|
||||
StmtIteratorBase() : stmt(0), decl(0), RawVAPtr(0) {}
|
||||
};
|
||||
@ -86,7 +86,7 @@ class StmtIteratorImpl : public StmtIteratorBase,
|
||||
StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {}
|
||||
StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {}
|
||||
StmtIteratorImpl(Decl *d, Stmt **s) : StmtIteratorBase(d, s) {}
|
||||
StmtIteratorImpl(VariableArrayType* t) : StmtIteratorBase(t) {}
|
||||
StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {}
|
||||
|
||||
DERIVED& operator++() {
|
||||
if (inDecl() || inDeclGroup()) {
|
||||
@ -130,7 +130,7 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
||||
StmtIterator(Decl** dgi, Decl** dge)
|
||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {}
|
||||
|
||||
StmtIterator(VariableArrayType* t)
|
||||
StmtIterator(const VariableArrayType *t)
|
||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
|
||||
|
||||
StmtIterator(Decl* D, Stmt **s = 0)
|
||||
@ -146,6 +146,86 @@ struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
||||
StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
|
||||
};
|
||||
|
||||
/// A range of statement iterators.
|
||||
///
|
||||
/// This class provides some extra functionality beyond std::pair
|
||||
/// in order to allow the following idiom:
|
||||
/// for (StmtRange range = stmt->children(); range; ++range)
|
||||
struct StmtRange : std::pair<StmtIterator,StmtIterator> {
|
||||
StmtRange() {}
|
||||
StmtRange(const StmtIterator &begin, const StmtIterator &end)
|
||||
: std::pair<StmtIterator,StmtIterator>(begin, end) {}
|
||||
|
||||
bool empty() const { return first == second; }
|
||||
operator bool() const { return !empty(); }
|
||||
|
||||
Stmt *operator->() const { return first.operator->(); }
|
||||
Stmt *&operator*() const { return first.operator*(); }
|
||||
|
||||
StmtRange &operator++() {
|
||||
assert(!empty() && "incrementing on empty range");
|
||||
++first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
StmtRange operator++(int) {
|
||||
assert(!empty() && "incrementing on empty range");
|
||||
StmtRange copy = *this;
|
||||
++first;
|
||||
return copy;
|
||||
}
|
||||
|
||||
friend const StmtIterator &begin(const StmtRange &range) {
|
||||
return range.first;
|
||||
}
|
||||
friend const StmtIterator &end(const StmtRange &range) {
|
||||
return range.second;
|
||||
}
|
||||
};
|
||||
|
||||
/// A range of const statement iterators.
|
||||
///
|
||||
/// This class provides some extra functionality beyond std::pair
|
||||
/// in order to allow the following idiom:
|
||||
/// for (ConstStmtRange range = stmt->children(); range; ++range)
|
||||
struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> {
|
||||
ConstStmtRange() {}
|
||||
ConstStmtRange(const ConstStmtIterator &begin,
|
||||
const ConstStmtIterator &end)
|
||||
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
|
||||
ConstStmtRange(const StmtRange &range)
|
||||
: std::pair<ConstStmtIterator,ConstStmtIterator>(range.first, range.second)
|
||||
{}
|
||||
ConstStmtRange(const StmtIterator &begin, const StmtIterator &end)
|
||||
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
|
||||
|
||||
bool empty() const { return first == second; }
|
||||
operator bool() const { return !empty(); }
|
||||
|
||||
const Stmt *operator->() const { return first.operator->(); }
|
||||
const Stmt *operator*() const { return first.operator*(); }
|
||||
|
||||
ConstStmtRange &operator++() {
|
||||
assert(!empty() && "incrementing on empty range");
|
||||
++first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConstStmtRange operator++(int) {
|
||||
assert(!empty() && "incrementing on empty range");
|
||||
ConstStmtRange copy = *this;
|
||||
++first;
|
||||
return copy;
|
||||
}
|
||||
|
||||
friend const ConstStmtIterator &begin(const ConstStmtRange &range) {
|
||||
return range.first;
|
||||
}
|
||||
friend const ConstStmtIterator &end(const ConstStmtRange &range) {
|
||||
return range.second;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -55,7 +55,7 @@ class ObjCForCollectionStmt : public Stmt {
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
@ -64,8 +64,9 @@ class ObjCForCollectionStmt : public Stmt {
|
||||
static bool classof(const ObjCForCollectionStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[END_EXPR]);
|
||||
}
|
||||
};
|
||||
|
||||
/// ObjCAtCatchStmt - This represents objective-c's @catch statement.
|
||||
@ -102,7 +103,7 @@ class ObjCAtCatchStmt : public Stmt {
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(AtCatchLoc, Body->getLocEnd());
|
||||
}
|
||||
|
||||
@ -113,8 +114,7 @@ class ObjCAtCatchStmt : public Stmt {
|
||||
}
|
||||
static bool classof(const ObjCAtCatchStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(&Body, &Body + 1); }
|
||||
};
|
||||
|
||||
/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement
|
||||
@ -133,7 +133,7 @@ class ObjCAtFinallyStmt : public Stmt {
|
||||
Stmt *getFinallyBody() { return AtFinallyStmt; }
|
||||
void setFinallyBody(Stmt *S) { AtFinallyStmt = S; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd());
|
||||
}
|
||||
|
||||
@ -145,8 +145,9 @@ class ObjCAtFinallyStmt : public Stmt {
|
||||
}
|
||||
static bool classof(const ObjCAtFinallyStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(&AtFinallyStmt, &AtFinallyStmt+1);
|
||||
}
|
||||
};
|
||||
|
||||
/// ObjCAtTryStmt - This represent objective-c's over-all
|
||||
@ -239,15 +240,17 @@ class ObjCAtTryStmt : public Stmt {
|
||||
getStmts()[1 + NumCatchStmts] = S;
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const;
|
||||
SourceRange getSourceRange() const;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtTryStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtTryStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(getStmts(),
|
||||
getStmts() + 1 + NumCatchStmts + HasFinally);
|
||||
}
|
||||
};
|
||||
|
||||
/// ObjCAtSynchronizedStmt - This is for objective-c's @synchronized statement.
|
||||
@ -291,7 +294,7 @@ class ObjCAtSynchronizedStmt : public Stmt {
|
||||
}
|
||||
void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd());
|
||||
}
|
||||
|
||||
@ -300,8 +303,9 @@ class ObjCAtSynchronizedStmt : public Stmt {
|
||||
}
|
||||
static bool classof(const ObjCAtSynchronizedStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() {
|
||||
return child_range(&SubStmts[0], &SubStmts[0]+END_EXPR);
|
||||
}
|
||||
};
|
||||
|
||||
/// ObjCAtThrowStmt - This represents objective-c's @throw statement.
|
||||
@ -323,7 +327,7 @@ class ObjCAtThrowStmt : public Stmt {
|
||||
SourceLocation getThrowLoc() { return AtThrowLoc; }
|
||||
void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const {
|
||||
if (Throw)
|
||||
return SourceRange(AtThrowLoc, Throw->getLocEnd());
|
||||
else
|
||||
@ -335,8 +339,7 @@ class ObjCAtThrowStmt : public Stmt {
|
||||
}
|
||||
static bool classof(const ObjCAtThrowStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
child_range children() { return child_range(&Throw, &Throw+1); }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
namespace llvm {
|
||||
class FoldingSetNodeID;
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -30,26 +31,14 @@ namespace clang {
|
||||
class Decl;
|
||||
class DiagnosticBuilder;
|
||||
class Expr;
|
||||
struct PrintingPolicy;
|
||||
class TypeSourceInfo;
|
||||
|
||||
/// \brief Represents a template argument within a class template
|
||||
/// specialization.
|
||||
class TemplateArgument {
|
||||
union {
|
||||
uintptr_t TypeOrValue;
|
||||
struct {
|
||||
char Value[sizeof(llvm::APSInt)];
|
||||
void *Type;
|
||||
} Integer;
|
||||
struct {
|
||||
TemplateArgument *Args;
|
||||
unsigned NumArgs;
|
||||
bool CopyArgs;
|
||||
} Args;
|
||||
};
|
||||
|
||||
public:
|
||||
/// \brief The type of template argument we're storing.
|
||||
/// \brief The kind of template argument we're storing.
|
||||
enum ArgKind {
|
||||
/// \brief Represents an empty template argument, e.g., one that has not
|
||||
/// been deduced.
|
||||
@ -66,16 +55,42 @@ class TemplateArgument {
|
||||
/// The template argument is a template name that was provided for a
|
||||
/// template template parameter.
|
||||
Template,
|
||||
/// The template argument is a pack expansion of a template name that was
|
||||
/// provided for a template template parameter.
|
||||
TemplateExpansion,
|
||||
/// The template argument is a value- or type-dependent expression
|
||||
/// stored in an Expr*.
|
||||
Expression,
|
||||
/// The template argument is actually a parameter pack. Arguments are stored
|
||||
/// in the Args struct.
|
||||
Pack
|
||||
} Kind;
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief The kind of template argument we're storing.
|
||||
unsigned Kind;
|
||||
|
||||
union {
|
||||
uintptr_t TypeOrValue;
|
||||
struct {
|
||||
char Value[sizeof(llvm::APSInt)];
|
||||
void *Type;
|
||||
} Integer;
|
||||
struct {
|
||||
const TemplateArgument *Args;
|
||||
unsigned NumArgs;
|
||||
} Args;
|
||||
struct {
|
||||
void *Name;
|
||||
unsigned NumExpansions;
|
||||
} TemplateArg;
|
||||
};
|
||||
|
||||
TemplateArgument(TemplateName, bool); // DO NOT USE
|
||||
|
||||
public:
|
||||
/// \brief Construct an empty, invalid template argument.
|
||||
TemplateArgument() : TypeOrValue(0), Kind(Null) { }
|
||||
TemplateArgument() : Kind(Null), TypeOrValue(0) { }
|
||||
|
||||
/// \brief Construct a template type argument.
|
||||
TemplateArgument(QualType T) : Kind(Type) {
|
||||
@ -92,6 +107,8 @@ class TemplateArgument {
|
||||
|
||||
/// \brief Construct an integral constant template argument.
|
||||
TemplateArgument(const llvm::APSInt &Value, QualType Type) : Kind(Integral) {
|
||||
// FIXME: Large integral values will get leaked. Do something
|
||||
// similar to what we did with IntegerLiteral.
|
||||
new (Integer.Value) llvm::APSInt(Value);
|
||||
Integer.Type = Type.getAsOpaquePtr();
|
||||
}
|
||||
@ -102,10 +119,35 @@ class TemplateArgument {
|
||||
/// parameters. However, the template name could be a dependent template
|
||||
/// name that ends up being instantiated to a function template whose address
|
||||
/// is taken.
|
||||
TemplateArgument(TemplateName Name) : Kind(Template) {
|
||||
TypeOrValue = reinterpret_cast<uintptr_t>(Name.getAsVoidPointer());
|
||||
///
|
||||
/// \param Name The template name.
|
||||
TemplateArgument(TemplateName Name) : Kind(Template)
|
||||
{
|
||||
TemplateArg.Name = Name.getAsVoidPointer();
|
||||
TemplateArg.NumExpansions = 0;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Construct a template argument that is a template pack expansion.
|
||||
///
|
||||
/// This form of template argument is generally used for template template
|
||||
/// parameters. However, the template name could be a dependent template
|
||||
/// name that ends up being instantiated to a function template whose address
|
||||
/// is taken.
|
||||
///
|
||||
/// \param Name The template name.
|
||||
///
|
||||
/// \param NumExpansions The number of expansions that will be generated by
|
||||
/// instantiating
|
||||
TemplateArgument(TemplateName Name, llvm::Optional<unsigned> NumExpansions)
|
||||
: Kind(TemplateExpansion)
|
||||
{
|
||||
TemplateArg.Name = Name.getAsVoidPointer();
|
||||
if (NumExpansions)
|
||||
TemplateArg.NumExpansions = *NumExpansions + 1;
|
||||
else
|
||||
TemplateArg.NumExpansions = 0;
|
||||
}
|
||||
|
||||
/// \brief Construct a template argument that is an expression.
|
||||
///
|
||||
/// This form of template argument only occurs in template argument
|
||||
@ -115,46 +157,59 @@ class TemplateArgument {
|
||||
TypeOrValue = reinterpret_cast<uintptr_t>(E);
|
||||
}
|
||||
|
||||
/// \brief Construct a template argument that is a template argument pack.
|
||||
///
|
||||
/// We assume that storage for the template arguments provided
|
||||
/// outlives the TemplateArgument itself.
|
||||
TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) : Kind(Pack){
|
||||
this->Args.Args = Args;
|
||||
this->Args.NumArgs = NumArgs;
|
||||
}
|
||||
|
||||
/// \brief Copy constructor for a template argument.
|
||||
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
|
||||
// FIXME: Large integral values will get leaked. Do something
|
||||
// similar to what we did with IntegerLiteral.
|
||||
if (Kind == Integral) {
|
||||
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
|
||||
Integer.Type = Other.Integer.Type;
|
||||
} else if (Kind == Pack) {
|
||||
Args.NumArgs = Other.Args.NumArgs;
|
||||
Args.Args = new TemplateArgument[Args.NumArgs];
|
||||
for (unsigned I = 0; I != Args.NumArgs; ++I)
|
||||
Args.Args[I] = Other.Args.Args[I];
|
||||
}
|
||||
else
|
||||
Args.Args = Other.Args.Args;
|
||||
} else if (Kind == Template || Kind == TemplateExpansion) {
|
||||
TemplateArg.Name = Other.TemplateArg.Name;
|
||||
TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
|
||||
} else
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
}
|
||||
|
||||
TemplateArgument& operator=(const TemplateArgument& Other) {
|
||||
// FIXME: Does not provide the strong guarantee for exception
|
||||
// safety.
|
||||
using llvm::APSInt;
|
||||
|
||||
// FIXME: Handle Packs
|
||||
assert(Kind != Pack && "FIXME: Handle packs");
|
||||
assert(Other.Kind != Pack && "FIXME: Handle packs");
|
||||
|
||||
if (Kind == Other.Kind && Kind == Integral) {
|
||||
// Copy integral values.
|
||||
*this->getAsIntegral() = *Other.getAsIntegral();
|
||||
Integer.Type = Other.Integer.Type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Destroy the current integral value, if that's what we're holding.
|
||||
if (Kind == Integral)
|
||||
getAsIntegral()->~APSInt();
|
||||
|
||||
Kind = Other.Kind;
|
||||
|
||||
if (Other.Kind == Integral) {
|
||||
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
|
||||
Integer.Type = Other.Integer.Type;
|
||||
} else if (Other.Kind == Pack) {
|
||||
Args.NumArgs = Other.Args.NumArgs;
|
||||
Args.Args = Other.Args.Args;
|
||||
} else if (Kind == Template || Kind == TemplateExpansion) {
|
||||
TemplateArg.Name = Other.TemplateArg.Name;
|
||||
TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
|
||||
} else {
|
||||
// Destroy the current integral value, if that's what we're holding.
|
||||
if (Kind == Integral)
|
||||
getAsIntegral()->~APSInt();
|
||||
|
||||
Kind = Other.Kind;
|
||||
|
||||
if (Other.Kind == Integral) {
|
||||
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
|
||||
Integer.Type = Other.Integer.Type;
|
||||
} else
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
}
|
||||
|
||||
return *this;
|
||||
@ -165,16 +220,31 @@ class TemplateArgument {
|
||||
|
||||
if (Kind == Integral)
|
||||
getAsIntegral()->~APSInt();
|
||||
else if (Kind == Pack && Args.CopyArgs)
|
||||
delete[] Args.Args;
|
||||
}
|
||||
|
||||
/// \brief Create a new template argument pack by copying the given set of
|
||||
/// template arguments.
|
||||
static TemplateArgument CreatePackCopy(ASTContext &Context,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs);
|
||||
|
||||
/// \brief Return the kind of stored template argument.
|
||||
ArgKind getKind() const { return Kind; }
|
||||
ArgKind getKind() const { return (ArgKind)Kind; }
|
||||
|
||||
/// \brief Determine whether this template argument has no value.
|
||||
bool isNull() const { return Kind == Null; }
|
||||
|
||||
/// \brief Whether this template argument is dependent on a template
|
||||
/// parameter.
|
||||
bool isDependent() const;
|
||||
|
||||
/// \brief Whether this template argument contains an unexpanded
|
||||
/// parameter pack.
|
||||
bool containsUnexpandedParameterPack() const;
|
||||
|
||||
/// \brief Determine whether this template argument is a pack expansion.
|
||||
bool isPackExpansion() const;
|
||||
|
||||
/// \brief Retrieve the template argument as a type.
|
||||
QualType getAsType() const {
|
||||
if (Kind != Type)
|
||||
@ -195,9 +265,21 @@ class TemplateArgument {
|
||||
if (Kind != Template)
|
||||
return TemplateName();
|
||||
|
||||
return TemplateName::getFromVoidPointer(
|
||||
reinterpret_cast<void *> (TypeOrValue));
|
||||
return TemplateName::getFromVoidPointer(TemplateArg.Name);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as a template name; if the argument
|
||||
/// is a pack expansion, return the pattern as a template name.
|
||||
TemplateName getAsTemplateOrTemplatePattern() const {
|
||||
if (Kind != Template && Kind != TemplateExpansion)
|
||||
return TemplateName();
|
||||
|
||||
return TemplateName::getFromVoidPointer(TemplateArg.Name);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the number of expansions that a template template argument
|
||||
/// expansion will produce, if known.
|
||||
llvm::Optional<unsigned> getNumTemplateExpansions() const;
|
||||
|
||||
/// \brief Retrieve the template argument as an integral value.
|
||||
llvm::APSInt *getAsIntegral() {
|
||||
@ -260,11 +342,17 @@ class TemplateArgument {
|
||||
/// same.
|
||||
bool structurallyEquals(const TemplateArgument &Other) const;
|
||||
|
||||
/// \brief Construct a template argument pack.
|
||||
void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs);
|
||||
/// \brief When the template argument is a pack expansion, returns
|
||||
/// the pattern of the pack expansion.
|
||||
///
|
||||
/// \param Ellipsis Will be set to the location of the ellipsis.
|
||||
TemplateArgument getPackExpansionPattern() const;
|
||||
|
||||
/// \brief Print this template argument to the given output stream.
|
||||
void print(const PrintingPolicy &Policy, llvm::raw_ostream &Out) const;
|
||||
|
||||
/// \brief Used to insert TemplateArguments into FoldingSets.
|
||||
void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context) const;
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
|
||||
};
|
||||
|
||||
/// Location information for a TemplateArgument.
|
||||
@ -276,95 +364,48 @@ struct TemplateArgumentLocInfo {
|
||||
struct {
|
||||
unsigned QualifierRange[2];
|
||||
unsigned TemplateNameLoc;
|
||||
unsigned EllipsisLoc;
|
||||
} Template;
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
enum Kind {
|
||||
K_None,
|
||||
K_TypeSourceInfo,
|
||||
K_Expression,
|
||||
K_Template
|
||||
} Kind;
|
||||
#endif
|
||||
|
||||
public:
|
||||
TemplateArgumentLocInfo()
|
||||
: Expression(0)
|
||||
#ifndef NDEBUG
|
||||
, Kind(K_None)
|
||||
#endif
|
||||
{}
|
||||
TemplateArgumentLocInfo();
|
||||
|
||||
TemplateArgumentLocInfo(TypeSourceInfo *TInfo)
|
||||
: Declarator(TInfo)
|
||||
#ifndef NDEBUG
|
||||
, Kind(K_TypeSourceInfo)
|
||||
#endif
|
||||
{}
|
||||
TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {}
|
||||
|
||||
TemplateArgumentLocInfo(Expr *E)
|
||||
: Expression(E)
|
||||
#ifndef NDEBUG
|
||||
, Kind(K_Expression)
|
||||
#endif
|
||||
{}
|
||||
TemplateArgumentLocInfo(Expr *E) : Expression(E) {}
|
||||
|
||||
TemplateArgumentLocInfo(SourceRange QualifierRange,
|
||||
SourceLocation TemplateNameLoc)
|
||||
#ifndef NDEBUG
|
||||
: Kind(K_Template)
|
||||
#endif
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation EllipsisLoc)
|
||||
{
|
||||
Template.QualifierRange[0] = QualifierRange.getBegin().getRawEncoding();
|
||||
Template.QualifierRange[1] = QualifierRange.getEnd().getRawEncoding();
|
||||
Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding();
|
||||
Template.EllipsisLoc = EllipsisLoc.getRawEncoding();
|
||||
}
|
||||
|
||||
TypeSourceInfo *getAsTypeSourceInfo() const {
|
||||
assert(Kind == K_TypeSourceInfo);
|
||||
return Declarator;
|
||||
}
|
||||
|
||||
Expr *getAsExpr() const {
|
||||
assert(Kind == K_Expression);
|
||||
return Expression;
|
||||
}
|
||||
|
||||
SourceRange getTemplateQualifierRange() const {
|
||||
assert(Kind == K_Template);
|
||||
return SourceRange(
|
||||
SourceLocation::getFromRawEncoding(Template.QualifierRange[0]),
|
||||
SourceLocation::getFromRawEncoding(Template.QualifierRange[1]));
|
||||
}
|
||||
|
||||
SourceLocation getTemplateNameLoc() const {
|
||||
assert(Kind == K_Template);
|
||||
return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void validateForArgument(const TemplateArgument &Arg) {
|
||||
switch (Arg.getKind()) {
|
||||
case TemplateArgument::Type:
|
||||
assert(Kind == K_TypeSourceInfo);
|
||||
break;
|
||||
case TemplateArgument::Expression:
|
||||
case TemplateArgument::Declaration:
|
||||
assert(Kind == K_Expression);
|
||||
break;
|
||||
case TemplateArgument::Template:
|
||||
assert(Kind == K_Template);
|
||||
break;
|
||||
case TemplateArgument::Integral:
|
||||
case TemplateArgument::Pack:
|
||||
assert(Kind == K_None);
|
||||
break;
|
||||
case TemplateArgument::Null:
|
||||
llvm_unreachable("source info for null template argument?");
|
||||
}
|
||||
SourceLocation getTemplateEllipsisLoc() const {
|
||||
return SourceLocation::getFromRawEncoding(Template.EllipsisLoc);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Location wrapper for a TemplateArgument. TemplateArgument is to
|
||||
@ -393,14 +434,18 @@ class TemplateArgumentLoc {
|
||||
|
||||
TemplateArgumentLoc(const TemplateArgument &Argument,
|
||||
SourceRange QualifierRange,
|
||||
SourceLocation TemplateNameLoc)
|
||||
: Argument(Argument), LocInfo(QualifierRange, TemplateNameLoc) {
|
||||
assert(Argument.getKind() == TemplateArgument::Template);
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation EllipsisLoc = SourceLocation())
|
||||
: Argument(Argument),
|
||||
LocInfo(QualifierRange, TemplateNameLoc, EllipsisLoc) {
|
||||
assert(Argument.getKind() == TemplateArgument::Template ||
|
||||
Argument.getKind() == TemplateArgument::TemplateExpansion);
|
||||
}
|
||||
|
||||
/// \brief - Fetches the primary location of the argument.
|
||||
SourceLocation getLocation() const {
|
||||
if (Argument.getKind() == TemplateArgument::Template)
|
||||
if (Argument.getKind() == TemplateArgument::Template ||
|
||||
Argument.getKind() == TemplateArgument::TemplateExpansion)
|
||||
return getTemplateNameLoc();
|
||||
|
||||
return getSourceRange().getBegin();
|
||||
@ -433,14 +478,32 @@ class TemplateArgumentLoc {
|
||||
}
|
||||
|
||||
SourceRange getTemplateQualifierRange() const {
|
||||
assert(Argument.getKind() == TemplateArgument::Template);
|
||||
assert(Argument.getKind() == TemplateArgument::Template ||
|
||||
Argument.getKind() == TemplateArgument::TemplateExpansion);
|
||||
return LocInfo.getTemplateQualifierRange();
|
||||
}
|
||||
|
||||
SourceLocation getTemplateNameLoc() const {
|
||||
assert(Argument.getKind() == TemplateArgument::Template);
|
||||
assert(Argument.getKind() == TemplateArgument::Template ||
|
||||
Argument.getKind() == TemplateArgument::TemplateExpansion);
|
||||
return LocInfo.getTemplateNameLoc();
|
||||
}
|
||||
|
||||
SourceLocation getTemplateEllipsisLoc() const {
|
||||
assert(Argument.getKind() == TemplateArgument::TemplateExpansion);
|
||||
return LocInfo.getTemplateEllipsisLoc();
|
||||
}
|
||||
|
||||
/// \brief When the template argument is a pack expansion, returns
|
||||
/// the pattern of the pack expansion.
|
||||
///
|
||||
/// \param Ellipsis Will be set to the location of the ellipsis.
|
||||
///
|
||||
/// \param NumExpansions Will be set to the number of expansions that will
|
||||
/// be generated from this pack expansion, if known a priori.
|
||||
TemplateArgumentLoc getPackExpansionPattern(SourceLocation &Ellipsis,
|
||||
llvm::Optional<unsigned> &NumExpansions,
|
||||
ASTContext &Context) const;
|
||||
};
|
||||
|
||||
/// A convenient class for passing around template argument
|
||||
|
@ -23,43 +23,119 @@ namespace llvm {
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class ASTContext;
|
||||
class DependentTemplateName;
|
||||
class DiagnosticBuilder;
|
||||
class IdentifierInfo;
|
||||
class NestedNameSpecifier;
|
||||
class OverloadedTemplateStorage;
|
||||
struct PrintingPolicy;
|
||||
class QualifiedTemplateName;
|
||||
class NamedDecl;
|
||||
class SubstTemplateTemplateParmPackStorage;
|
||||
class TemplateArgument;
|
||||
class TemplateDecl;
|
||||
|
||||
class TemplateTemplateParmDecl;
|
||||
|
||||
/// \brief Implementation class used to describe either a set of overloaded
|
||||
/// template names or an already-substituted template template parameter pack.
|
||||
class UncommonTemplateNameStorage {
|
||||
protected:
|
||||
union {
|
||||
struct {
|
||||
/// \brief If true, this is an OverloadedTemplateStorage instance;
|
||||
/// otherwise, it's a SubstTemplateTemplateParmPackStorage instance.
|
||||
unsigned IsOverloadedStorage : 1;
|
||||
|
||||
/// \brief The number of stored templates or template arguments,
|
||||
/// depending on which subclass we have.
|
||||
unsigned Size : 31;
|
||||
} Bits;
|
||||
|
||||
void *PointerAlignment;
|
||||
};
|
||||
|
||||
UncommonTemplateNameStorage(unsigned Size, bool OverloadedStorage) {
|
||||
Bits.IsOverloadedStorage = OverloadedStorage;
|
||||
Bits.Size = Size;
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned size() const { return Bits.Size; }
|
||||
|
||||
OverloadedTemplateStorage *getAsOverloadedStorage() {
|
||||
return Bits.IsOverloadedStorage
|
||||
? reinterpret_cast<OverloadedTemplateStorage *>(this)
|
||||
: 0;
|
||||
}
|
||||
|
||||
SubstTemplateTemplateParmPackStorage *getAsSubstTemplateTemplateParmPack() {
|
||||
return Bits.IsOverloadedStorage
|
||||
? 0
|
||||
: reinterpret_cast<SubstTemplateTemplateParmPackStorage *>(this) ;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A structure for storing the information associated with an
|
||||
/// overloaded template name.
|
||||
class OverloadedTemplateStorage {
|
||||
union {
|
||||
unsigned Size;
|
||||
NamedDecl *Storage[1];
|
||||
};
|
||||
|
||||
class OverloadedTemplateStorage : public UncommonTemplateNameStorage {
|
||||
friend class ASTContext;
|
||||
|
||||
OverloadedTemplateStorage(unsigned Size) : Size(Size) {}
|
||||
OverloadedTemplateStorage(unsigned Size)
|
||||
: UncommonTemplateNameStorage(Size, true) { }
|
||||
|
||||
NamedDecl **getStorage() {
|
||||
return &Storage[1];
|
||||
return reinterpret_cast<NamedDecl **>(this + 1);
|
||||
}
|
||||
NamedDecl * const *getStorage() const {
|
||||
return &Storage[1];
|
||||
return reinterpret_cast<NamedDecl *const *>(this + 1);
|
||||
}
|
||||
|
||||
public:
|
||||
typedef NamedDecl *const *iterator;
|
||||
|
||||
unsigned size() const { return Size; }
|
||||
|
||||
iterator begin() const { return getStorage(); }
|
||||
iterator end() const { return getStorage() + size(); }
|
||||
};
|
||||
|
||||
|
||||
/// \brief A structure for storing an already-substituted template template
|
||||
/// parameter pack.
|
||||
///
|
||||
/// This kind of template names occurs when the parameter pack has been
|
||||
/// provided with a template template argument pack in a context where its
|
||||
/// enclosing pack expansion could not be fully expanded.
|
||||
class SubstTemplateTemplateParmPackStorage
|
||||
: public UncommonTemplateNameStorage, public llvm::FoldingSetNode
|
||||
{
|
||||
ASTContext &Context;
|
||||
TemplateTemplateParmDecl *Parameter;
|
||||
const TemplateArgument *Arguments;
|
||||
|
||||
public:
|
||||
SubstTemplateTemplateParmPackStorage(ASTContext &Context,
|
||||
TemplateTemplateParmDecl *Parameter,
|
||||
unsigned Size,
|
||||
const TemplateArgument *Arguments)
|
||||
: UncommonTemplateNameStorage(Size, false), Context(Context),
|
||||
Parameter(Parameter), Arguments(Arguments) { }
|
||||
|
||||
/// \brief Retrieve the template template parameter pack being substituted.
|
||||
TemplateTemplateParmDecl *getParameterPack() const {
|
||||
return Parameter;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template template argument pack with which this
|
||||
/// parameter was substituted.
|
||||
TemplateArgument getArgumentPack() const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
|
||||
TemplateTemplateParmDecl *Parameter,
|
||||
const TemplateArgument &ArgPack);
|
||||
};
|
||||
|
||||
/// \brief Represents a C++ template name within the type system.
|
||||
///
|
||||
@ -90,7 +166,7 @@ class OverloadedTemplateStorage {
|
||||
/// only be understood in the context of
|
||||
class TemplateName {
|
||||
typedef llvm::PointerUnion4<TemplateDecl *,
|
||||
OverloadedTemplateStorage *,
|
||||
UncommonTemplateNameStorage *,
|
||||
QualifiedTemplateName *,
|
||||
DependentTemplateName *> StorageType;
|
||||
|
||||
@ -103,16 +179,28 @@ class TemplateName {
|
||||
public:
|
||||
// \brief Kind of name that is actually stored.
|
||||
enum NameKind {
|
||||
/// \brief A single template declaration.
|
||||
Template,
|
||||
/// \brief A set of overloaded template declarations.
|
||||
OverloadedTemplate,
|
||||
/// \brief A qualified template name, where the qualification is kept
|
||||
/// to describe the source code as written.
|
||||
QualifiedTemplate,
|
||||
DependentTemplate
|
||||
/// \brief A dependent template name that has not been resolved to a
|
||||
/// template (or set of templates).
|
||||
DependentTemplate,
|
||||
/// \brief A template template parameter pack that has been substituted for
|
||||
/// a template template argument pack, but has not yet been expanded into
|
||||
/// individual arguments.
|
||||
SubstTemplateTemplateParmPack
|
||||
};
|
||||
|
||||
TemplateName() : Storage() { }
|
||||
explicit TemplateName(TemplateDecl *Template) : Storage(Template) { }
|
||||
explicit TemplateName(OverloadedTemplateStorage *Storage)
|
||||
: Storage(Storage) { }
|
||||
explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
|
||||
: Storage(Storage) { }
|
||||
explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { }
|
||||
explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { }
|
||||
|
||||
@ -122,7 +210,7 @@ class TemplateName {
|
||||
// \brief Get the kind of name that is actually stored.
|
||||
NameKind getKind() const;
|
||||
|
||||
/// \brief Retrieve the the underlying template declaration that
|
||||
/// \brief Retrieve the underlying template declaration that
|
||||
/// this template name refers to, if known.
|
||||
///
|
||||
/// \returns The template declaration that this template name refers
|
||||
@ -131,7 +219,7 @@ class TemplateName {
|
||||
/// set of function templates, returns NULL.
|
||||
TemplateDecl *getAsTemplateDecl() const;
|
||||
|
||||
/// \brief Retrieve the the underlying, overloaded function template
|
||||
/// \brief Retrieve the underlying, overloaded function template
|
||||
// declarations that this template name refers to, if known.
|
||||
///
|
||||
/// \returns The set of overloaded function templates that this template
|
||||
@ -139,7 +227,25 @@ class TemplateName {
|
||||
/// specific set of function templates because it is a dependent name or
|
||||
/// refers to a single template, returns NULL.
|
||||
OverloadedTemplateStorage *getAsOverloadedTemplate() const {
|
||||
return Storage.dyn_cast<OverloadedTemplateStorage *>();
|
||||
if (UncommonTemplateNameStorage *Uncommon =
|
||||
Storage.dyn_cast<UncommonTemplateNameStorage *>())
|
||||
return Uncommon->getAsOverloadedStorage();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the substituted template template parameter pack, if
|
||||
/// known.
|
||||
///
|
||||
/// \returns The storage for the substituted template template parameter pack,
|
||||
/// if known. Otherwise, returns NULL.
|
||||
SubstTemplateTemplateParmPackStorage *
|
||||
getAsSubstTemplateTemplateParmPack() const {
|
||||
if (UncommonTemplateNameStorage *Uncommon =
|
||||
Storage.dyn_cast<UncommonTemplateNameStorage *>())
|
||||
return Uncommon->getAsSubstTemplateTemplateParmPack();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the underlying qualified template name
|
||||
@ -157,6 +263,10 @@ class TemplateName {
|
||||
/// \brief Determines whether this is a dependent template name.
|
||||
bool isDependent() const;
|
||||
|
||||
/// \brief Determines whether this template name contains an
|
||||
/// unexpanded parameter pack (for C++0x variadic templates).
|
||||
bool containsUnexpandedParameterPack() const;
|
||||
|
||||
/// \brief Print the template name.
|
||||
///
|
||||
/// \param OS the output stream to which the template name will be
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class ParmVarDecl;
|
||||
class TypeSourceInfo;
|
||||
class UnqualTypeLoc;
|
||||
@ -38,7 +39,7 @@ class TypeLoc {
|
||||
protected:
|
||||
// The correctness of this relies on the property that, for Type *Ty,
|
||||
// QualType(Ty, 0).getAsOpaquePtr() == (void*) Ty
|
||||
void *Ty;
|
||||
const void *Ty;
|
||||
void *Data;
|
||||
|
||||
public:
|
||||
@ -56,7 +57,7 @@ class TypeLoc {
|
||||
TypeLoc() : Ty(0), Data(0) { }
|
||||
TypeLoc(QualType ty, void *opaqueData)
|
||||
: Ty(ty.getAsOpaquePtr()), Data(opaqueData) { }
|
||||
TypeLoc(Type *ty, void *opaqueData)
|
||||
TypeLoc(const Type *ty, void *opaqueData)
|
||||
: Ty(ty), Data(opaqueData) { }
|
||||
|
||||
TypeLocClass getTypeLocClass() const {
|
||||
@ -76,7 +77,7 @@ class TypeLoc {
|
||||
return QualType::getFromOpaquePtr(Ty);
|
||||
}
|
||||
|
||||
Type *getTypePtr() const {
|
||||
const Type *getTypePtr() const {
|
||||
return QualType::getFromOpaquePtr(Ty).getTypePtr();
|
||||
}
|
||||
|
||||
@ -115,13 +116,36 @@ class TypeLoc {
|
||||
/// \brief Skips past any qualifiers, if this is qualified.
|
||||
UnqualTypeLoc getUnqualifiedLoc() const; // implemented in this header
|
||||
|
||||
TypeLoc IgnoreParens() const {
|
||||
if (isa<ParenTypeLoc>(this))
|
||||
return IgnoreParensImpl(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Initializes this to state that every location in this
|
||||
/// type is the given location.
|
||||
///
|
||||
/// This method exists to provide a simple transition for code that
|
||||
/// relies on location-less types.
|
||||
void initialize(SourceLocation Loc) const {
|
||||
initializeImpl(*this, Loc);
|
||||
void initialize(ASTContext &Context, SourceLocation Loc) const {
|
||||
initializeImpl(Context, *this, Loc);
|
||||
}
|
||||
|
||||
/// \brief Initializes this by copying its information from another
|
||||
/// TypeLoc of the same type.
|
||||
void initializeFullCopy(TypeLoc Other) const {
|
||||
assert(getType() == Other.getType());
|
||||
size_t Size = getFullDataSize();
|
||||
memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
|
||||
}
|
||||
|
||||
/// \brief Initializes this by copying its information from another
|
||||
/// TypeLoc of the same type. The given size must be the full data
|
||||
/// size.
|
||||
void initializeFullCopy(TypeLoc Other, unsigned Size) const {
|
||||
assert(getType() == Other.getType());
|
||||
assert(getFullDataSize() == Size);
|
||||
memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
|
||||
}
|
||||
|
||||
friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) {
|
||||
@ -135,8 +159,9 @@ class TypeLoc {
|
||||
static bool classof(const TypeLoc *TL) { return true; }
|
||||
|
||||
private:
|
||||
static void initializeImpl(TypeLoc TL, SourceLocation Loc);
|
||||
static void initializeImpl(ASTContext &Context, TypeLoc TL, SourceLocation Loc);
|
||||
static TypeLoc getNextTypeLocImpl(TypeLoc TL);
|
||||
static TypeLoc IgnoreParensImpl(TypeLoc TL);
|
||||
static SourceRange getLocalSourceRangeImpl(TypeLoc TL);
|
||||
};
|
||||
|
||||
@ -146,14 +171,14 @@ inline TypeLoc TypeSourceInfo::getTypeLoc() const {
|
||||
}
|
||||
|
||||
/// \brief Wrapper of type source information for a type with
|
||||
/// no direct quqlaifiers.
|
||||
/// no direct qualifiers.
|
||||
class UnqualTypeLoc : public TypeLoc {
|
||||
public:
|
||||
UnqualTypeLoc() {}
|
||||
UnqualTypeLoc(Type *Ty, void *Data) : TypeLoc(Ty, Data) {}
|
||||
UnqualTypeLoc(const Type *Ty, void *Data) : TypeLoc(Ty, Data) {}
|
||||
|
||||
Type *getTypePtr() const {
|
||||
return reinterpret_cast<Type*>(Ty);
|
||||
const Type *getTypePtr() const {
|
||||
return reinterpret_cast<const Type*>(Ty);
|
||||
}
|
||||
|
||||
TypeLocClass getTypeLocClass() const {
|
||||
@ -183,7 +208,7 @@ class QualifiedTypeLoc : public TypeLoc {
|
||||
|
||||
/// Initializes the local data of this type source info block to
|
||||
/// provide no information.
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@ -282,7 +307,7 @@ class ConcreteTypeLoc : public Base {
|
||||
return getNextTypeLoc(asDerived()->getInnerType());
|
||||
}
|
||||
|
||||
TypeClass *getTypePtr() const {
|
||||
const TypeClass *getTypePtr() const {
|
||||
return cast<TypeClass>(Base::getTypePtr());
|
||||
}
|
||||
|
||||
@ -355,7 +380,7 @@ class InheritingConcreteTypeLoc : public Base {
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeClass *getTypePtr() const {
|
||||
const TypeClass *getTypePtr() const {
|
||||
return cast<TypeClass>(Base::getTypePtr());
|
||||
}
|
||||
};
|
||||
@ -383,7 +408,7 @@ class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
SourceRange getLocalSourceRange() const {
|
||||
return SourceRange(getNameLoc(), getNameLoc());
|
||||
}
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setNameLoc(Loc);
|
||||
}
|
||||
|
||||
@ -484,7 +509,7 @@ class BuiltinTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
getWrittenBuiltinSpecs().ModeAttr = written;
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setBuiltinLoc(Loc);
|
||||
if (needsExtraLocalData()) {
|
||||
WrittenBuiltinSpecs &wbs = getWrittenBuiltinSpecs();
|
||||
@ -568,6 +593,137 @@ class SubstTemplateTypeParmTypeLoc :
|
||||
SubstTemplateTypeParmType> {
|
||||
};
|
||||
|
||||
/// \brief Wrapper for substituted template type parameters.
|
||||
class SubstTemplateTypeParmPackTypeLoc :
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
SubstTemplateTypeParmPackTypeLoc,
|
||||
SubstTemplateTypeParmPackType> {
|
||||
};
|
||||
|
||||
struct AttributedLocInfo {
|
||||
union {
|
||||
Expr *ExprOperand;
|
||||
|
||||
/// A raw SourceLocation.
|
||||
unsigned EnumOperandLoc;
|
||||
};
|
||||
|
||||
SourceRange OperandParens;
|
||||
|
||||
SourceLocation AttrLoc;
|
||||
};
|
||||
|
||||
/// \brief Type source information for an attributed type.
|
||||
class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
AttributedTypeLoc,
|
||||
AttributedType,
|
||||
AttributedLocInfo> {
|
||||
public:
|
||||
AttributedType::Kind getAttrKind() const {
|
||||
return getTypePtr()->getAttrKind();
|
||||
}
|
||||
|
||||
bool hasAttrExprOperand() const {
|
||||
return (getAttrKind() >= AttributedType::FirstExprOperandKind &&
|
||||
getAttrKind() <= AttributedType::LastExprOperandKind);
|
||||
}
|
||||
|
||||
bool hasAttrEnumOperand() const {
|
||||
return (getAttrKind() >= AttributedType::FirstEnumOperandKind &&
|
||||
getAttrKind() <= AttributedType::LastEnumOperandKind);
|
||||
}
|
||||
|
||||
bool hasAttrOperand() const {
|
||||
return hasAttrExprOperand() || hasAttrEnumOperand();
|
||||
}
|
||||
|
||||
/// The modified type, which is generally canonically different from
|
||||
/// the attribute type.
|
||||
/// int main(int, char**) __attribute__((noreturn))
|
||||
/// ~~~ ~~~~~~~~~~~~~
|
||||
TypeLoc getModifiedLoc() const {
|
||||
return getInnerTypeLoc();
|
||||
}
|
||||
|
||||
/// The location of the attribute name, i.e.
|
||||
/// __attribute__((regparm(1000)))
|
||||
/// ^~~~~~~
|
||||
SourceLocation getAttrNameLoc() const {
|
||||
return getLocalData()->AttrLoc;
|
||||
}
|
||||
void setAttrNameLoc(SourceLocation loc) {
|
||||
getLocalData()->AttrLoc = loc;
|
||||
}
|
||||
|
||||
/// The attribute's expression operand, if it has one.
|
||||
/// void *cur_thread __attribute__((address_space(21)))
|
||||
/// ^~
|
||||
Expr *getAttrExprOperand() const {
|
||||
assert(hasAttrExprOperand());
|
||||
return getLocalData()->ExprOperand;
|
||||
}
|
||||
void setAttrExprOperand(Expr *e) {
|
||||
assert(hasAttrExprOperand());
|
||||
getLocalData()->ExprOperand = e;
|
||||
}
|
||||
|
||||
/// The location of the attribute's enumerated operand, if it has one.
|
||||
/// void * __attribute__((objc_gc(weak)))
|
||||
/// ^~~~
|
||||
SourceLocation getAttrEnumOperandLoc() const {
|
||||
assert(hasAttrEnumOperand());
|
||||
return SourceLocation::getFromRawEncoding(getLocalData()->EnumOperandLoc);
|
||||
}
|
||||
void setAttrEnumOperandLoc(SourceLocation loc) {
|
||||
assert(hasAttrEnumOperand());
|
||||
getLocalData()->EnumOperandLoc = loc.getRawEncoding();
|
||||
}
|
||||
|
||||
/// The location of the parentheses around the operand, if there is
|
||||
/// an operand.
|
||||
/// void * __attribute__((objc_gc(weak)))
|
||||
/// ^ ^
|
||||
SourceRange getAttrOperandParensRange() const {
|
||||
assert(hasAttrOperand());
|
||||
return getLocalData()->OperandParens;
|
||||
}
|
||||
void setAttrOperandParensRange(SourceRange range) {
|
||||
assert(hasAttrOperand());
|
||||
getLocalData()->OperandParens = range;
|
||||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
// Note that this does *not* include the range of the attribute
|
||||
// enclosure, e.g.:
|
||||
// __attribute__((foo(bar)))
|
||||
// ^~~~~~~~~~~~~~~ ~~
|
||||
// or
|
||||
// [[foo(bar)]]
|
||||
// ^~ ~~
|
||||
// That enclosure doesn't necessarily belong to a single attribute
|
||||
// anyway.
|
||||
SourceRange range(getAttrNameLoc());
|
||||
if (hasAttrOperand())
|
||||
range.setEnd(getAttrOperandParensRange().getEnd());
|
||||
return range;
|
||||
}
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation loc) {
|
||||
setAttrNameLoc(loc);
|
||||
if (hasAttrExprOperand()) {
|
||||
setAttrOperandParensRange(SourceRange(loc));
|
||||
setAttrExprOperand(0);
|
||||
} else if (hasAttrEnumOperand()) {
|
||||
setAttrOperandParensRange(SourceRange(loc));
|
||||
setAttrEnumOperandLoc(loc);
|
||||
}
|
||||
}
|
||||
|
||||
QualType getInnerType() const {
|
||||
return getTypePtr()->getModifiedType();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ObjCProtocolListLocInfo {
|
||||
SourceLocation LAngleLoc;
|
||||
@ -638,7 +794,7 @@ class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
return SourceRange(getLAngleLoc(), getRAngleLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setHasBaseTypeAsWritten(true);
|
||||
setLAngleLoc(Loc);
|
||||
setRAngleLoc(Loc);
|
||||
@ -682,11 +838,51 @@ class ObjCInterfaceTypeLoc : public ConcreteTypeLoc<ObjCObjectTypeLoc,
|
||||
return SourceRange(getNameLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setNameLoc(Loc);
|
||||
}
|
||||
};
|
||||
|
||||
struct ParenLocInfo {
|
||||
SourceLocation LParenLoc;
|
||||
SourceLocation RParenLoc;
|
||||
};
|
||||
|
||||
class ParenTypeLoc
|
||||
: public ConcreteTypeLoc<UnqualTypeLoc, ParenTypeLoc, ParenType,
|
||||
ParenLocInfo> {
|
||||
public:
|
||||
SourceLocation getLParenLoc() const {
|
||||
return this->getLocalData()->LParenLoc;
|
||||
}
|
||||
SourceLocation getRParenLoc() const {
|
||||
return this->getLocalData()->RParenLoc;
|
||||
}
|
||||
void setLParenLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->LParenLoc = Loc;
|
||||
}
|
||||
void setRParenLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->RParenLoc = Loc;
|
||||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
return SourceRange(getLParenLoc(), getRParenLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setLParenLoc(Loc);
|
||||
setRParenLoc(Loc);
|
||||
}
|
||||
|
||||
TypeLoc getInnerLoc() const {
|
||||
return getInnerTypeLoc();
|
||||
}
|
||||
|
||||
QualType getInnerType() const {
|
||||
return this->getTypePtr()->getInnerType();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct PointerLikeLocInfo {
|
||||
SourceLocation StarLoc;
|
||||
@ -712,7 +908,7 @@ class PointerLikeTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, Derived,
|
||||
return SourceRange(getSigilLoc(), getSigilLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setSigilLoc(Loc);
|
||||
}
|
||||
|
||||
@ -812,6 +1008,7 @@ class RValueReferenceTypeLoc :
|
||||
|
||||
struct FunctionLocInfo {
|
||||
SourceLocation LParenLoc, RParenLoc;
|
||||
bool TrailingReturn;
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for functions.
|
||||
@ -819,11 +1016,6 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
FunctionTypeLoc,
|
||||
FunctionType,
|
||||
FunctionLocInfo> {
|
||||
// ParmVarDecls* are stored after Info, one for each argument.
|
||||
ParmVarDecl **getParmArray() const {
|
||||
return (ParmVarDecl**) getExtraLocalData();
|
||||
}
|
||||
|
||||
public:
|
||||
SourceLocation getLParenLoc() const {
|
||||
return getLocalData()->LParenLoc;
|
||||
@ -839,6 +1031,18 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
getLocalData()->RParenLoc = Loc;
|
||||
}
|
||||
|
||||
bool getTrailingReturn() const {
|
||||
return getLocalData()->TrailingReturn;
|
||||
}
|
||||
void setTrailingReturn(bool Trailing) {
|
||||
getLocalData()->TrailingReturn = Trailing;
|
||||
}
|
||||
|
||||
// ParmVarDecls* are stored after Info, one for each argument.
|
||||
ParmVarDecl **getParmArray() const {
|
||||
return (ParmVarDecl**) getExtraLocalData();
|
||||
}
|
||||
|
||||
unsigned getNumArgs() const {
|
||||
if (isa<FunctionNoProtoType>(getTypePtr()))
|
||||
return 0;
|
||||
@ -855,9 +1059,10 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
return SourceRange(getLParenLoc(), getRParenLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setLParenLoc(Loc);
|
||||
setRParenLoc(Loc);
|
||||
setTrailingReturn(false);
|
||||
for (unsigned i = 0, e = getNumArgs(); i != e; ++i)
|
||||
setArg(i, NULL);
|
||||
}
|
||||
@ -928,7 +1133,7 @@ class ArrayTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
return SourceRange(getLBracketLoc(), getRBracketLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setLBracketLoc(Loc);
|
||||
setRBracketLoc(Loc);
|
||||
setSizeExpr(NULL);
|
||||
@ -997,9 +1202,6 @@ class TemplateSpecializationTypeLoc :
|
||||
return getTypePtr()->getNumArgs();
|
||||
}
|
||||
void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) {
|
||||
#ifndef NDEBUG
|
||||
AI.validateForArgument(getTypePtr()->getArg(i));
|
||||
#endif
|
||||
getArgInfos()[i] = AI;
|
||||
}
|
||||
TemplateArgumentLocInfo getArgLocInfo(unsigned i) const {
|
||||
@ -1033,47 +1235,18 @@ class TemplateSpecializationTypeLoc :
|
||||
return SourceRange(getTemplateNameLoc(), getRAngleLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setLAngleLoc(Loc);
|
||||
setRAngleLoc(Loc);
|
||||
setTemplateNameLoc(Loc);
|
||||
initializeArgLocs(getNumArgs(), getTypePtr()->getArgs(),
|
||||
initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(),
|
||||
getArgInfos(), Loc);
|
||||
}
|
||||
|
||||
static void initializeArgLocs(unsigned NumArgs,
|
||||
static void initializeArgLocs(ASTContext &Context, unsigned NumArgs,
|
||||
const TemplateArgument *Args,
|
||||
TemplateArgumentLocInfo *ArgInfos,
|
||||
SourceLocation Loc) {
|
||||
for (unsigned i = 0, e = NumArgs; i != e; ++i) {
|
||||
TemplateArgumentLocInfo Info;
|
||||
#ifndef NDEBUG
|
||||
// If asserts are enabled, be sure to initialize the argument
|
||||
// loc with the right kind of pointer.
|
||||
switch (Args[i].getKind()) {
|
||||
case TemplateArgument::Expression:
|
||||
case TemplateArgument::Declaration:
|
||||
Info = TemplateArgumentLocInfo((Expr*) 0);
|
||||
break;
|
||||
|
||||
case TemplateArgument::Type:
|
||||
Info = TemplateArgumentLocInfo((TypeSourceInfo*) 0);
|
||||
break;
|
||||
|
||||
case TemplateArgument::Template:
|
||||
Info = TemplateArgumentLocInfo(SourceRange(Loc), Loc);
|
||||
break;
|
||||
|
||||
case TemplateArgument::Integral:
|
||||
case TemplateArgument::Pack:
|
||||
case TemplateArgument::Null:
|
||||
// K_None is fine.
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
ArgInfos[i] = Info;
|
||||
}
|
||||
}
|
||||
SourceLocation Loc);
|
||||
|
||||
unsigned getExtraLocalDataSize() const {
|
||||
return getNumArgs() * sizeof(TemplateArgumentLocInfo);
|
||||
@ -1168,7 +1341,7 @@ class TypeofLikeTypeLoc
|
||||
return SourceRange(getTypeofLoc(), getRParenLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setTypeofLoc(Loc);
|
||||
setLParenLoc(Loc);
|
||||
setRParenLoc(Loc);
|
||||
@ -1208,6 +1381,11 @@ class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
DecltypeType> {
|
||||
};
|
||||
|
||||
class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
AutoTypeLoc,
|
||||
AutoType> {
|
||||
};
|
||||
|
||||
struct ElaboratedLocInfo {
|
||||
SourceLocation KeywordLoc;
|
||||
SourceRange QualifierRange;
|
||||
@ -1242,7 +1420,7 @@ class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
return getQualifierRange();
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setKeywordLoc(Loc);
|
||||
setQualifierRange(SourceRange(Loc));
|
||||
}
|
||||
@ -1307,7 +1485,7 @@ class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
memcpy(Data, Loc.Data, size);
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setKeywordLoc(Loc);
|
||||
setQualifierRange(SourceRange(Loc));
|
||||
setNameLoc(Loc);
|
||||
@ -1368,9 +1546,6 @@ class DependentTemplateSpecializationTypeLoc :
|
||||
}
|
||||
|
||||
void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) {
|
||||
#ifndef NDEBUG
|
||||
AI.validateForArgument(getTypePtr()->getArg(i));
|
||||
#endif
|
||||
getArgInfos()[i] = AI;
|
||||
}
|
||||
TemplateArgumentLocInfo getArgLocInfo(unsigned i) const {
|
||||
@ -1394,13 +1569,13 @@ class DependentTemplateSpecializationTypeLoc :
|
||||
memcpy(Data, Loc.Data, size);
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setKeywordLoc(Loc);
|
||||
setQualifierRange(SourceRange(Loc));
|
||||
setNameLoc(Loc);
|
||||
setLAngleLoc(Loc);
|
||||
setRAngleLoc(Loc);
|
||||
TemplateSpecializationTypeLoc::initializeArgLocs(getNumArgs(),
|
||||
TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
|
||||
getTypePtr()->getArgs(),
|
||||
getArgInfos(), Loc);
|
||||
}
|
||||
@ -1415,6 +1590,40 @@ class DependentTemplateSpecializationTypeLoc :
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct PackExpansionTypeLocInfo {
|
||||
SourceLocation EllipsisLoc;
|
||||
};
|
||||
|
||||
class PackExpansionTypeLoc
|
||||
: public ConcreteTypeLoc<UnqualTypeLoc, PackExpansionTypeLoc,
|
||||
PackExpansionType, PackExpansionTypeLocInfo> {
|
||||
public:
|
||||
SourceLocation getEllipsisLoc() const {
|
||||
return this->getLocalData()->EllipsisLoc;
|
||||
}
|
||||
|
||||
void setEllipsisLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->EllipsisLoc = Loc;
|
||||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
return SourceRange(getEllipsisLoc(), getEllipsisLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setEllipsisLoc(Loc);
|
||||
}
|
||||
|
||||
TypeLoc getPatternLoc() const {
|
||||
return getInnerTypeLoc();
|
||||
}
|
||||
|
||||
QualType getInnerType() const {
|
||||
return this->getTypePtr()->getPattern();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -79,6 +79,7 @@ ABSTRACT_TYPE(Function, Type)
|
||||
TYPE(FunctionProto, FunctionType)
|
||||
TYPE(FunctionNoProto, FunctionType)
|
||||
DEPENDENT_TYPE(UnresolvedUsing, Type)
|
||||
NON_CANONICAL_TYPE(Paren, Type)
|
||||
NON_CANONICAL_TYPE(Typedef, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type)
|
||||
@ -87,12 +88,16 @@ ABSTRACT_TYPE(Tag, Type)
|
||||
TYPE(Record, TagType)
|
||||
TYPE(Enum, TagType)
|
||||
NON_CANONICAL_TYPE(Elaborated, Type)
|
||||
NON_CANONICAL_TYPE(Attributed, Type)
|
||||
DEPENDENT_TYPE(TemplateTypeParm, Type)
|
||||
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
|
||||
DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Auto, Type)
|
||||
DEPENDENT_TYPE(InjectedClassName, Type)
|
||||
DEPENDENT_TYPE(DependentName, Type)
|
||||
DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
|
||||
DEPENDENT_TYPE(PackExpansion, Type)
|
||||
TYPE(ObjCObject, Type)
|
||||
TYPE(ObjCInterface, ObjCObjectType)
|
||||
TYPE(ObjCObjectPointer, Type)
|
||||
|
@ -19,12 +19,13 @@
|
||||
namespace clang {
|
||||
|
||||
#define DISPATCH(CLASS) \
|
||||
return static_cast<ImplClass*>(this)->Visit ## CLASS(static_cast<CLASS*>(T))
|
||||
return static_cast<ImplClass*>(this)-> \
|
||||
Visit##CLASS(static_cast<const CLASS*>(T))
|
||||
|
||||
template<typename ImplClass, typename RetTy=void>
|
||||
class TypeVisitor {
|
||||
public:
|
||||
RetTy Visit(Type *T) {
|
||||
RetTy Visit(const Type *T) {
|
||||
// Top switch stmt: dispatch to VisitFooType for each FooType.
|
||||
switch (T->getTypeClass()) {
|
||||
default: assert(0 && "Unknown type class!");
|
||||
@ -36,13 +37,13 @@ class TypeVisitor {
|
||||
|
||||
// If the implementation chooses not to implement a certain visit method, fall
|
||||
// back on superclass.
|
||||
#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(CLASS##Type *T) { \
|
||||
#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(const CLASS##Type *T) { \
|
||||
DISPATCH(PARENT); \
|
||||
}
|
||||
#include "clang/AST/TypeNodes.def"
|
||||
|
||||
// Base case, ignore it. :)
|
||||
RetTy VisitType(Type*) { return RetTy(); }
|
||||
RetTy VisitType(const Type*) { return RetTy(); }
|
||||
};
|
||||
|
||||
#undef DISPATCH
|
||||
|
@ -379,6 +379,7 @@ using analyze_format_string::OptionalAmount;
|
||||
using analyze_format_string::OptionalFlag;
|
||||
|
||||
class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
|
||||
OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
|
||||
OptionalFlag IsLeftJustified; // '-'
|
||||
OptionalFlag HasPlusPrefix; // '+'
|
||||
OptionalFlag HasSpacePrefix; // ' '
|
||||
@ -388,8 +389,8 @@ class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
|
||||
public:
|
||||
PrintfSpecifier() :
|
||||
FormatSpecifier(/* isPrintf = */ true),
|
||||
IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
|
||||
HasAlternativeForm("#"), HasLeadingZeroes("0") {}
|
||||
HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"),
|
||||
HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0") {}
|
||||
|
||||
static PrintfSpecifier Parse(const char *beg, const char *end);
|
||||
|
||||
@ -397,6 +398,10 @@ class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
|
||||
void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
|
||||
CS = cs;
|
||||
}
|
||||
void setHasThousandsGrouping(const char *position) {
|
||||
HasThousandsGrouping = true;
|
||||
HasThousandsGrouping.setPosition(position);
|
||||
}
|
||||
void setIsLeftJustified(const char *position) {
|
||||
IsLeftJustified = true;
|
||||
IsLeftJustified.setPosition(position);
|
||||
@ -445,6 +450,9 @@ class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
|
||||
/// more than one type.
|
||||
ArgTypeResult getArgType(ASTContext &Ctx) const;
|
||||
|
||||
const OptionalFlag &hasThousandsGrouping() const {
|
||||
return HasThousandsGrouping;
|
||||
}
|
||||
const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
|
||||
const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
|
||||
const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
|
||||
@ -465,6 +473,7 @@ class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
|
||||
bool hasValidLeadingZeros() const;
|
||||
bool hasValidSpacePrefix() const;
|
||||
bool hasValidLeftJustified() const;
|
||||
bool hasValidThousandsGroupingPrefix() const;
|
||||
|
||||
bool hasValidPrecision() const;
|
||||
bool hasValidFieldWidth() const;
|
||||
|
@ -55,7 +55,8 @@ struct LiveVariables_ValueTypes {
|
||||
|
||||
/// ObserveStmt - A callback invoked right before invoking the
|
||||
/// liveness transfer function on the given statement.
|
||||
virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD,
|
||||
virtual void ObserveStmt(Stmt* S, const CFGBlock *currentBlock,
|
||||
const AnalysisDataTy& AD,
|
||||
const ValTy& V) {}
|
||||
|
||||
virtual void ObserverKill(DeclRefExpr* DR) {}
|
||||
|
40
include/clang/Analysis/Analyses/UninitializedValuesV2.h
Normal file
40
include/clang/Analysis/Analyses/UninitializedValuesV2.h
Normal file
@ -0,0 +1,40 @@
|
||||
//= UninitializedValuesV2.h - Finding uses of uninitialized values --*- C++ -*-=
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines APIs for invoking and reported uninitialized values
|
||||
// warnings.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_UNINIT_VALS_H
|
||||
#define LLVM_CLANG_UNINIT_VALS_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
class AnalysisContext;
|
||||
class CFG;
|
||||
class DeclContext;
|
||||
class Expr;
|
||||
class VarDecl;
|
||||
|
||||
class UninitVariablesHandler {
|
||||
public:
|
||||
UninitVariablesHandler() {}
|
||||
virtual ~UninitVariablesHandler();
|
||||
|
||||
virtual void handleUseOfUninitVariable(const Expr *ex,
|
||||
const VarDecl *vd) {}
|
||||
};
|
||||
|
||||
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
|
||||
AnalysisContext &ac,
|
||||
UninitVariablesHandler &handler);
|
||||
|
||||
}
|
||||
#endif
|
@ -16,6 +16,7 @@
|
||||
#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
@ -56,15 +57,20 @@ class AnalysisContext {
|
||||
llvm::BumpPtrAllocator A;
|
||||
bool UseUnoptimizedCFG;
|
||||
bool AddEHEdges;
|
||||
bool AddImplicitDtors;
|
||||
bool AddInitializers;
|
||||
public:
|
||||
AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
|
||||
bool useUnoptimizedCFG = false,
|
||||
bool addehedges = false)
|
||||
bool addehedges = false,
|
||||
bool addImplicitDtors = false,
|
||||
bool addInitializers = false)
|
||||
: D(d), TU(tu), cfg(0), completeCFG(0),
|
||||
builtCFG(false), builtCompleteCFG(false),
|
||||
liveness(0), relaxedLiveness(0), PM(0), PCA(0),
|
||||
ReferencedBlockVars(0), UseUnoptimizedCFG(useUnoptimizedCFG),
|
||||
AddEHEdges(addehedges) {}
|
||||
AddEHEdges(addehedges), AddImplicitDtors(addImplicitDtors),
|
||||
AddInitializers(addInitializers) {}
|
||||
|
||||
~AnalysisContext();
|
||||
|
||||
@ -80,13 +86,17 @@ class AnalysisContext {
|
||||
bool getAddEHEdges() const { return AddEHEdges; }
|
||||
|
||||
bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; }
|
||||
bool getAddImplicitDtors() const { return AddImplicitDtors; }
|
||||
bool getAddInitializers() const { return AddInitializers; }
|
||||
|
||||
Stmt *getBody();
|
||||
CFG *getCFG();
|
||||
|
||||
|
||||
/// Return a version of the CFG without any edges pruned.
|
||||
CFG *getUnoptimizedCFG();
|
||||
|
||||
void dumpCFG();
|
||||
|
||||
ParentMap &getParentMap();
|
||||
PseudoConstantAnalysis *getPseudoConstantAnalysis();
|
||||
LiveVariables *getLiveVariables();
|
||||
@ -106,15 +116,21 @@ class AnalysisContextManager {
|
||||
typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
|
||||
ContextMap Contexts;
|
||||
bool UseUnoptimizedCFG;
|
||||
bool AddImplicitDtors;
|
||||
bool AddInitializers;
|
||||
public:
|
||||
AnalysisContextManager(bool useUnoptimizedCFG = false)
|
||||
: UseUnoptimizedCFG(useUnoptimizedCFG) {}
|
||||
AnalysisContextManager(bool useUnoptimizedCFG = false,
|
||||
bool addImplicitDtors = false, bool addInitializers = false)
|
||||
: UseUnoptimizedCFG(useUnoptimizedCFG), AddImplicitDtors(addImplicitDtors),
|
||||
AddInitializers(addInitializers) {}
|
||||
|
||||
~AnalysisContextManager();
|
||||
|
||||
AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
|
||||
|
||||
bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; }
|
||||
bool getAddImplicitDtors() const { return AddImplicitDtors; }
|
||||
bool getAddInitializers() const { return AddInitializers; }
|
||||
|
||||
// Discard all previously created AnalysisContexts.
|
||||
void clear();
|
||||
@ -196,9 +212,10 @@ class StackFrameContext : public LocationContext {
|
||||
|
||||
friend class LocationContextManager;
|
||||
StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
|
||||
const Stmt *s, const CFGBlock *blk, unsigned idx)
|
||||
: LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
|
||||
Index(idx) {}
|
||||
const Stmt *s, const CFGBlock *blk,
|
||||
unsigned idx)
|
||||
: LocationContext(StackFrame, ctx, parent), CallSite(s),
|
||||
Block(blk), Index(idx) {}
|
||||
|
||||
public:
|
||||
~StackFrameContext() {}
|
||||
@ -282,8 +299,8 @@ class LocationContextManager {
|
||||
|
||||
const StackFrameContext *getStackFrame(AnalysisContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const Stmt *s, const CFGBlock *blk,
|
||||
unsigned idx);
|
||||
const Stmt *s,
|
||||
const CFGBlock *blk, unsigned idx);
|
||||
|
||||
const ScopeContext *getScope(AnalysisContext *ctx,
|
||||
const LocationContext *parent,
|
||||
|
@ -15,7 +15,7 @@
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM,
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
|
||||
#define ANALYSISSTART
|
||||
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
|
||||
#undef DIAG
|
||||
|
@ -22,14 +22,21 @@
|
||||
#include "clang/Analysis/Support/BumpVector.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class Stmt;
|
||||
class Expr;
|
||||
class FieldDecl;
|
||||
class VarDecl;
|
||||
class CXXCtorInitializer;
|
||||
class CXXBaseSpecifier;
|
||||
class CXXBindTemporaryExpr;
|
||||
class CFG;
|
||||
class PrinterHelper;
|
||||
class LangOptions;
|
||||
@ -37,19 +44,203 @@ namespace clang {
|
||||
|
||||
/// CFGElement - Represents a top-level expression in a basic block.
|
||||
class CFGElement {
|
||||
llvm::PointerIntPair<Stmt *, 2> Data;
|
||||
public:
|
||||
enum Type { StartScope, EndScope };
|
||||
explicit CFGElement() {}
|
||||
CFGElement(Stmt *S, bool lvalue) : Data(S, lvalue ? 1 : 0) {}
|
||||
CFGElement(Stmt *S, Type t) : Data(S, t == StartScope ? 2 : 3) {}
|
||||
Stmt *getStmt() const { return Data.getPointer(); }
|
||||
bool asLValue() const { return Data.getInt() == 1; }
|
||||
bool asStartScope() const { return Data.getInt() == 2; }
|
||||
bool asEndScope() const { return Data.getInt() == 3; }
|
||||
bool asDtor() const { return Data.getInt() == 4; }
|
||||
enum Kind {
|
||||
// main kind
|
||||
Statement,
|
||||
Initializer,
|
||||
ImplicitDtor,
|
||||
// dtor kind
|
||||
AutomaticObjectDtor,
|
||||
BaseDtor,
|
||||
MemberDtor,
|
||||
TemporaryDtor,
|
||||
DTOR_BEGIN = AutomaticObjectDtor
|
||||
};
|
||||
|
||||
protected:
|
||||
// The int bits are used to mark the main kind.
|
||||
llvm::PointerIntPair<void *, 2> Data1;
|
||||
// The int bits are used to mark the dtor kind.
|
||||
llvm::PointerIntPair<void *, 2> Data2;
|
||||
|
||||
CFGElement(void *Ptr, unsigned Int) : Data1(Ptr, Int) {}
|
||||
CFGElement(void *Ptr1, unsigned Int1, void *Ptr2, unsigned Int2)
|
||||
: Data1(Ptr1, Int1), Data2(Ptr2, Int2) {}
|
||||
|
||||
public:
|
||||
CFGElement() {}
|
||||
|
||||
Kind getKind() const { return static_cast<Kind>(Data1.getInt()); }
|
||||
|
||||
Kind getDtorKind() const {
|
||||
assert(getKind() == ImplicitDtor);
|
||||
return static_cast<Kind>(Data2.getInt() + DTOR_BEGIN);
|
||||
}
|
||||
|
||||
bool isValid() const { return Data1.getPointer(); }
|
||||
|
||||
operator bool() const { return isValid(); }
|
||||
|
||||
template<class ElemTy> ElemTy getAs() const {
|
||||
if (llvm::isa<ElemTy>(this))
|
||||
return *static_cast<const ElemTy*>(this);
|
||||
return ElemTy();
|
||||
}
|
||||
|
||||
static bool classof(const CFGElement *E) { return true; }
|
||||
};
|
||||
|
||||
class CFGStmt : public CFGElement {
|
||||
public:
|
||||
CFGStmt() {}
|
||||
CFGStmt(Stmt *S) : CFGElement(S, 0) {}
|
||||
|
||||
Stmt *getStmt() const { return static_cast<Stmt *>(Data1.getPointer()); }
|
||||
|
||||
operator Stmt*() const { return getStmt(); }
|
||||
operator bool() const { return getStmt() != 0; }
|
||||
|
||||
static bool classof(const CFGElement *E) {
|
||||
return E->getKind() == Statement;
|
||||
}
|
||||
};
|
||||
|
||||
/// CFGInitializer - Represents C++ base or member initializer from
|
||||
/// constructor's initialization list.
|
||||
class CFGInitializer : public CFGElement {
|
||||
public:
|
||||
CFGInitializer() {}
|
||||
CFGInitializer(CXXCtorInitializer* I)
|
||||
: CFGElement(I, Initializer) {}
|
||||
|
||||
CXXCtorInitializer* getInitializer() const {
|
||||
return static_cast<CXXCtorInitializer*>(Data1.getPointer());
|
||||
}
|
||||
operator CXXCtorInitializer*() const { return getInitializer(); }
|
||||
|
||||
static bool classof(const CFGElement *E) {
|
||||
return E->getKind() == Initializer;
|
||||
}
|
||||
};
|
||||
|
||||
/// CFGImplicitDtor - Represents C++ object destructor implicitly generated
|
||||
/// by compiler on various occasions.
|
||||
class CFGImplicitDtor : public CFGElement {
|
||||
protected:
|
||||
CFGImplicitDtor(unsigned K, void* P, void* S)
|
||||
: CFGElement(P, ImplicitDtor, S, K - DTOR_BEGIN) {}
|
||||
|
||||
public:
|
||||
CFGImplicitDtor() {}
|
||||
|
||||
static bool classof(const CFGElement *E) {
|
||||
return E->getKind() == ImplicitDtor;
|
||||
}
|
||||
};
|
||||
|
||||
/// CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated
|
||||
/// for automatic object or temporary bound to const reference at the point
|
||||
/// of leaving its local scope.
|
||||
class CFGAutomaticObjDtor: public CFGImplicitDtor {
|
||||
public:
|
||||
CFGAutomaticObjDtor() {}
|
||||
CFGAutomaticObjDtor(VarDecl* VD, Stmt* S)
|
||||
: CFGImplicitDtor(AutomaticObjectDtor, VD, S) {}
|
||||
|
||||
VarDecl* getVarDecl() const {
|
||||
return static_cast<VarDecl*>(Data1.getPointer());
|
||||
}
|
||||
|
||||
// Get statement end of which triggered the destructor call.
|
||||
Stmt* getTriggerStmt() const {
|
||||
return static_cast<Stmt*>(Data2.getPointer());
|
||||
}
|
||||
|
||||
static bool classof(const CFGElement *E) {
|
||||
return E->getKind() == ImplicitDtor &&
|
||||
E->getDtorKind() == AutomaticObjectDtor;
|
||||
}
|
||||
};
|
||||
|
||||
/// CFGBaseDtor - Represents C++ object destructor implicitly generated for
|
||||
/// base object in destructor.
|
||||
class CFGBaseDtor : public CFGImplicitDtor {
|
||||
public:
|
||||
CFGBaseDtor() {}
|
||||
CFGBaseDtor(const CXXBaseSpecifier *BS)
|
||||
: CFGImplicitDtor(BaseDtor, const_cast<CXXBaseSpecifier*>(BS), NULL) {}
|
||||
|
||||
const CXXBaseSpecifier *getBaseSpecifier() const {
|
||||
return static_cast<const CXXBaseSpecifier*>(Data1.getPointer());
|
||||
}
|
||||
|
||||
static bool classof(const CFGElement *E) {
|
||||
return E->getKind() == ImplicitDtor && E->getDtorKind() == BaseDtor;
|
||||
}
|
||||
};
|
||||
|
||||
/// CFGMemberDtor - Represents C++ object destructor implicitly generated for
|
||||
/// member object in destructor.
|
||||
class CFGMemberDtor : public CFGImplicitDtor {
|
||||
public:
|
||||
CFGMemberDtor() {}
|
||||
CFGMemberDtor(FieldDecl *FD)
|
||||
: CFGImplicitDtor(MemberDtor, FD, NULL) {}
|
||||
|
||||
FieldDecl *getFieldDecl() const {
|
||||
return static_cast<FieldDecl*>(Data1.getPointer());
|
||||
}
|
||||
|
||||
static bool classof(const CFGElement *E) {
|
||||
return E->getKind() == ImplicitDtor && E->getDtorKind() == MemberDtor;
|
||||
}
|
||||
};
|
||||
|
||||
/// CFGTemporaryDtor - Represents C++ object destructor implicitly generated
|
||||
/// at the end of full expression for temporary object.
|
||||
class CFGTemporaryDtor : public CFGImplicitDtor {
|
||||
public:
|
||||
CFGTemporaryDtor() {}
|
||||
CFGTemporaryDtor(CXXBindTemporaryExpr *E)
|
||||
: CFGImplicitDtor(TemporaryDtor, E, NULL) {}
|
||||
|
||||
CXXBindTemporaryExpr *getBindTemporaryExpr() const {
|
||||
return static_cast<CXXBindTemporaryExpr *>(Data1.getPointer());
|
||||
}
|
||||
|
||||
static bool classof(const CFGElement *E) {
|
||||
return E->getKind() == ImplicitDtor && E->getDtorKind() == TemporaryDtor;
|
||||
}
|
||||
};
|
||||
|
||||
/// CFGTerminator - Represents CFGBlock terminator statement.
|
||||
///
|
||||
/// TemporaryDtorsBranch bit is set to true if the terminator marks a branch
|
||||
/// in control flow of destructors of temporaries. In this case terminator
|
||||
/// statement is the same statement that branches control flow in evaluation
|
||||
/// of matching full expression.
|
||||
class CFGTerminator {
|
||||
llvm::PointerIntPair<Stmt *, 1> Data;
|
||||
public:
|
||||
CFGTerminator() {}
|
||||
CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false)
|
||||
: Data(S, TemporaryDtorsBranch) {}
|
||||
|
||||
Stmt *getStmt() { return Data.getPointer(); }
|
||||
const Stmt *getStmt() const { return Data.getPointer(); }
|
||||
|
||||
bool isTemporaryDtorsBranch() const { return Data.getInt(); }
|
||||
|
||||
operator Stmt *() { return getStmt(); }
|
||||
operator const Stmt *() const { return getStmt(); }
|
||||
|
||||
Stmt *operator->() { return getStmt(); }
|
||||
const Stmt *operator->() const { return getStmt(); }
|
||||
|
||||
Stmt &operator*() { return *getStmt(); }
|
||||
const Stmt &operator*() const { return *getStmt(); }
|
||||
|
||||
operator bool() const { return getStmt(); }
|
||||
};
|
||||
|
||||
/// CFGBlock - Represents a single basic block in a source-level CFG.
|
||||
@ -77,11 +268,11 @@ class CFGElement {
|
||||
/// &&, || expression that uses result of && or ||, RHS
|
||||
///
|
||||
class CFGBlock {
|
||||
class StatementList {
|
||||
class ElementList {
|
||||
typedef BumpVector<CFGElement> ImplTy;
|
||||
ImplTy Impl;
|
||||
public:
|
||||
StatementList(BumpVectorContext &C) : Impl(C, 4) {}
|
||||
ElementList(BumpVectorContext &C) : Impl(C, 4) {}
|
||||
|
||||
typedef std::reverse_iterator<ImplTy::iterator> iterator;
|
||||
typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
|
||||
@ -89,6 +280,11 @@ class CFGBlock {
|
||||
typedef ImplTy::const_iterator const_reverse_iterator;
|
||||
|
||||
void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
|
||||
reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
|
||||
BumpVectorContext& C) {
|
||||
return Impl.insert(I, Cnt, E, C);
|
||||
}
|
||||
|
||||
CFGElement front() const { return Impl.back(); }
|
||||
CFGElement back() const { return Impl.front(); }
|
||||
|
||||
@ -111,7 +307,7 @@ class CFGBlock {
|
||||
};
|
||||
|
||||
/// Stmts - The set of statements in the basic block.
|
||||
StatementList Stmts;
|
||||
ElementList Elements;
|
||||
|
||||
/// Label - An (optional) label that prefixes the executable
|
||||
/// statements in the block. When this variable is non-NULL, it is
|
||||
@ -121,7 +317,7 @@ class CFGBlock {
|
||||
/// Terminator - The terminator for a basic block that
|
||||
/// indicates the type of control-flow that occurs between a block
|
||||
/// and its successors.
|
||||
Stmt *Terminator;
|
||||
CFGTerminator Terminator;
|
||||
|
||||
/// LoopTarget - Some blocks are used to represent the "loop edge" to
|
||||
/// the start of a loop from within the loop body. This Stmt* will be
|
||||
@ -140,33 +336,33 @@ class CFGBlock {
|
||||
|
||||
public:
|
||||
explicit CFGBlock(unsigned blockid, BumpVectorContext &C)
|
||||
: Stmts(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
|
||||
: Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
|
||||
BlockID(blockid), Preds(C, 1), Succs(C, 1) {}
|
||||
~CFGBlock() {}
|
||||
|
||||
// Statement iterators
|
||||
typedef StatementList::iterator iterator;
|
||||
typedef StatementList::const_iterator const_iterator;
|
||||
typedef StatementList::reverse_iterator reverse_iterator;
|
||||
typedef StatementList::const_reverse_iterator const_reverse_iterator;
|
||||
typedef ElementList::iterator iterator;
|
||||
typedef ElementList::const_iterator const_iterator;
|
||||
typedef ElementList::reverse_iterator reverse_iterator;
|
||||
typedef ElementList::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
CFGElement front() const { return Stmts.front(); }
|
||||
CFGElement back() const { return Stmts.back(); }
|
||||
CFGElement front() const { return Elements.front(); }
|
||||
CFGElement back() const { return Elements.back(); }
|
||||
|
||||
iterator begin() { return Stmts.begin(); }
|
||||
iterator end() { return Stmts.end(); }
|
||||
const_iterator begin() const { return Stmts.begin(); }
|
||||
const_iterator end() const { return Stmts.end(); }
|
||||
iterator begin() { return Elements.begin(); }
|
||||
iterator end() { return Elements.end(); }
|
||||
const_iterator begin() const { return Elements.begin(); }
|
||||
const_iterator end() const { return Elements.end(); }
|
||||
|
||||
reverse_iterator rbegin() { return Stmts.rbegin(); }
|
||||
reverse_iterator rend() { return Stmts.rend(); }
|
||||
const_reverse_iterator rbegin() const { return Stmts.rbegin(); }
|
||||
const_reverse_iterator rend() const { return Stmts.rend(); }
|
||||
reverse_iterator rbegin() { return Elements.rbegin(); }
|
||||
reverse_iterator rend() { return Elements.rend(); }
|
||||
const_reverse_iterator rbegin() const { return Elements.rbegin(); }
|
||||
const_reverse_iterator rend() const { return Elements.rend(); }
|
||||
|
||||
unsigned size() const { return Stmts.size(); }
|
||||
bool empty() const { return Stmts.empty(); }
|
||||
unsigned size() const { return Elements.size(); }
|
||||
bool empty() const { return Elements.empty(); }
|
||||
|
||||
CFGElement operator[](size_t i) const { return Stmts[i]; }
|
||||
CFGElement operator[](size_t i) const { return Elements[i]; }
|
||||
|
||||
// CFG iterators
|
||||
typedef AdjacentBlocks::iterator pred_iterator;
|
||||
@ -205,14 +401,67 @@ class CFGBlock {
|
||||
unsigned pred_size() const { return Preds.size(); }
|
||||
bool pred_empty() const { return Preds.empty(); }
|
||||
|
||||
|
||||
class FilterOptions {
|
||||
public:
|
||||
FilterOptions() {
|
||||
IgnoreDefaultsWithCoveredEnums = 0;
|
||||
}
|
||||
|
||||
unsigned IgnoreDefaultsWithCoveredEnums : 1;
|
||||
};
|
||||
|
||||
static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src,
|
||||
const CFGBlock *Dst);
|
||||
|
||||
template <typename IMPL, bool IsPred>
|
||||
class FilteredCFGBlockIterator {
|
||||
private:
|
||||
IMPL I, E;
|
||||
const FilterOptions F;
|
||||
const CFGBlock *From;
|
||||
public:
|
||||
explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e,
|
||||
const CFGBlock *from,
|
||||
const FilterOptions &f)
|
||||
: I(i), E(e), F(f), From(from) {}
|
||||
|
||||
bool hasMore() const { return I != E; }
|
||||
|
||||
FilteredCFGBlockIterator &operator++() {
|
||||
do { ++I; } while (hasMore() && Filter(*I));
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CFGBlock *operator*() const { return *I; }
|
||||
private:
|
||||
bool Filter(const CFGBlock *To) {
|
||||
return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To);
|
||||
}
|
||||
};
|
||||
|
||||
typedef FilteredCFGBlockIterator<const_pred_iterator, true>
|
||||
filtered_pred_iterator;
|
||||
|
||||
typedef FilteredCFGBlockIterator<const_succ_iterator, false>
|
||||
filtered_succ_iterator;
|
||||
|
||||
filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const {
|
||||
return filtered_pred_iterator(pred_begin(), pred_end(), this, f);
|
||||
}
|
||||
|
||||
filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const {
|
||||
return filtered_succ_iterator(succ_begin(), succ_end(), this, f);
|
||||
}
|
||||
|
||||
// Manipulation of block contents
|
||||
|
||||
void setTerminator(Stmt* Statement) { Terminator = Statement; }
|
||||
void setLabel(Stmt* Statement) { Label = Statement; }
|
||||
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
|
||||
|
||||
Stmt* getTerminator() { return Terminator; }
|
||||
const Stmt* getTerminator() const { return Terminator; }
|
||||
CFGTerminator getTerminator() { return Terminator; }
|
||||
const CFGTerminator getTerminator() const { return Terminator; }
|
||||
|
||||
Stmt* getTerminatorCondition();
|
||||
|
||||
@ -239,18 +488,40 @@ class CFGBlock {
|
||||
Succs.push_back(Block, C);
|
||||
}
|
||||
|
||||
void appendStmt(Stmt* Statement, BumpVectorContext &C, bool asLValue) {
|
||||
Stmts.push_back(CFGElement(Statement, asLValue), C);
|
||||
}
|
||||
void StartScope(Stmt* S, BumpVectorContext &C) {
|
||||
Stmts.push_back(CFGElement(S, CFGElement::StartScope), C);
|
||||
void appendStmt(Stmt* statement, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGStmt(statement), C);
|
||||
}
|
||||
void EndScope(Stmt* S, BumpVectorContext &C) {
|
||||
Stmts.push_back(CFGElement(S, CFGElement::EndScope), C);
|
||||
|
||||
void appendInitializer(CXXCtorInitializer *initializer,
|
||||
BumpVectorContext& C) {
|
||||
Elements.push_back(CFGInitializer(initializer), C);
|
||||
}
|
||||
|
||||
void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGBaseDtor(BS), C);
|
||||
}
|
||||
|
||||
void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGMemberDtor(FD), C);
|
||||
}
|
||||
|
||||
void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGTemporaryDtor(E), C);
|
||||
}
|
||||
|
||||
// Destructors must be inserted in reversed order. So insertion is in two
|
||||
// steps. First we prepare space for some number of elements, then we insert
|
||||
// the elements beginning at the last position in prepared space.
|
||||
iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
|
||||
BumpVectorContext& C) {
|
||||
return iterator(Elements.insert(I.base(), Cnt, CFGElement(), C));
|
||||
}
|
||||
iterator insertAutomaticObjDtor(iterator I, VarDecl* VD, Stmt* S) {
|
||||
*I = CFGAutomaticObjDtor(VD, S);
|
||||
return ++I;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// CFG - Represents a source-level, intra-procedural CFG that represents the
|
||||
/// control-flow of a Stmt. The Stmt can represent an entire function body,
|
||||
/// or a single expression. A CFG will always contain one empty block that
|
||||
@ -264,13 +535,24 @@ class CFG {
|
||||
// CFG Construction & Manipulation.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class BuildOptions {
|
||||
public:
|
||||
bool PruneTriviallyFalseEdges:1;
|
||||
bool AddEHEdges:1;
|
||||
bool AddInitializers:1;
|
||||
bool AddImplicitDtors:1;
|
||||
|
||||
BuildOptions()
|
||||
: PruneTriviallyFalseEdges(true)
|
||||
, AddEHEdges(false)
|
||||
, AddInitializers(false)
|
||||
, AddImplicitDtors(false) {}
|
||||
};
|
||||
|
||||
/// buildCFG - Builds a CFG from an AST. The responsibility to free the
|
||||
/// constructed CFG belongs to the caller.
|
||||
static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C,
|
||||
bool pruneTriviallyFalseEdges = true,
|
||||
bool AddEHEdges = false,
|
||||
bool AddScopes = false /* NOT FULLY IMPLEMENTED.
|
||||
NOT READY FOR GENERAL USE. */);
|
||||
BuildOptions BO = BuildOptions());
|
||||
|
||||
/// createBlock - Create a new block in the CFG. The CFG owns the block;
|
||||
/// the caller should not directly free it.
|
||||
@ -324,8 +606,10 @@ class CFG {
|
||||
void VisitBlockStmts(CALLBACK& O) const {
|
||||
for (const_iterator I=begin(), E=end(); I != E; ++I)
|
||||
for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end();
|
||||
BI != BE; ++BI)
|
||||
O(*BI);
|
||||
BI != BE; ++BI) {
|
||||
if (CFGStmt S = BI->getAs<CFGStmt>())
|
||||
O(S);
|
||||
}
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -340,7 +624,10 @@ class CFG {
|
||||
operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
|
||||
};
|
||||
|
||||
bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
|
||||
bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
|
||||
bool isBlkExpr(const Stmt *S) const {
|
||||
return const_cast<CFG*>(this)->isBlkExpr(S);
|
||||
}
|
||||
BlkExprNumTy getBlkExprNum(const Stmt* S);
|
||||
unsigned getNumBlkExprs();
|
||||
|
||||
@ -398,18 +685,22 @@ class CFG {
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Implement simplify_type for CFGElement, so that we can dyn_cast from
|
||||
/// CFGElement to a specific Stmt class.
|
||||
template <> struct simplify_type<const ::clang::CFGElement> {
|
||||
typedef ::clang::Stmt* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::CFGElement &Val) {
|
||||
/// Implement simplify_type for CFGTerminator, so that we can dyn_cast from
|
||||
/// CFGTerminator to a specific Stmt class.
|
||||
template <> struct simplify_type<const ::clang::CFGTerminator> {
|
||||
typedef const ::clang::Stmt *SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) {
|
||||
return Val.getStmt();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct simplify_type< ::clang::CFGElement>
|
||||
: public simplify_type<const ::clang::CFGElement> {};
|
||||
|
||||
|
||||
template <> struct simplify_type< ::clang::CFGTerminator> {
|
||||
typedef ::clang::Stmt *SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) {
|
||||
return const_cast<SimpleType>(Val.getStmt());
|
||||
}
|
||||
};
|
||||
|
||||
// Traits for: CFGBlock
|
||||
|
||||
template <> struct GraphTraits< ::clang::CFGBlock* > {
|
||||
|
@ -11,17 +11,18 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_CHECKER_DS_COCOA
|
||||
#define LLVM_CLANG_CHECKER_DS_COCOA
|
||||
#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA
|
||||
#define LLVM_CLANG_ANALYSIS_DS_COCOA
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
namespace cocoa {
|
||||
|
||||
enum NamingConvention { NoConvention, CreateRule, InitRule };
|
||||
|
||||
NamingConvention deriveNamingConvention(Selector S);
|
||||
NamingConvention deriveNamingConvention(Selector S, bool ignorePrefix = true);
|
||||
|
||||
static inline bool followsFundamentalRule(Selector S) {
|
||||
return deriveNamingConvention(S) == CreateRule;
|
||||
@ -34,6 +35,6 @@ namespace cocoa {
|
||||
|
||||
bool isCocoaObjectRef(QualType T);
|
||||
|
||||
}}
|
||||
}}}
|
||||
|
||||
#endif
|
@ -273,8 +273,13 @@ class DataflowSolver {
|
||||
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
|
||||
dataflow::forward_analysis_tag) {
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
|
||||
ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
|
||||
TF.setCurrentBlock(B);
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
|
||||
CFGElement El = *I;
|
||||
if (CFGStmt S = El.getAs<CFGStmt>())
|
||||
ProcessStmt(S, recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
}
|
||||
@ -282,10 +287,15 @@ class DataflowSolver {
|
||||
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
|
||||
dataflow::backward_analysis_tag) {
|
||||
|
||||
TF.setCurrentBlock(B);
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
|
||||
ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
|
||||
CFGElement El = *I;
|
||||
if (CFGStmt S = El.getAs<CFGStmt>())
|
||||
ProcessStmt(S, recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) {
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
@ -44,6 +44,7 @@ class ProgramPoint {
|
||||
PostPurgeDeadSymbolsKind,
|
||||
PostStmtCustomKind,
|
||||
PostLValueKind,
|
||||
PostInitializerKind,
|
||||
CallEnterKind,
|
||||
CallExitKind,
|
||||
MinPostStmtKind = PostStmtKind,
|
||||
@ -70,11 +71,12 @@ class ProgramPoint {
|
||||
protected:
|
||||
const void* getData1() const { return Data.first; }
|
||||
const void* getData2() const { return Data.second; }
|
||||
const void *getTag() const { return Tag; }
|
||||
|
||||
public:
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
const void *getTag() const { return Tag; }
|
||||
|
||||
const LocationContext *getLocationContext() const { return L; }
|
||||
|
||||
// For use with DenseMap. This hash is probably slow.
|
||||
@ -118,10 +120,12 @@ class BlockEntrance : public ProgramPoint {
|
||||
return B->empty() ? CFGElement() : B->front();
|
||||
}
|
||||
|
||||
const Stmt *getFirstStmt() const {
|
||||
return getFirstElement().getStmt();
|
||||
/// Create a new BlockEntrance object that is the same as the original
|
||||
/// except for using the specified tag value.
|
||||
BlockEntrance withTag(const void *tag) {
|
||||
return BlockEntrance(getBlock(), getLocationContext(), tag);
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == BlockEntranceKind;
|
||||
}
|
||||
@ -136,11 +140,6 @@ class BlockExit : public ProgramPoint {
|
||||
return reinterpret_cast<const CFGBlock*>(getData1());
|
||||
}
|
||||
|
||||
const Stmt* getLastStmt() const {
|
||||
const CFGBlock* B = getBlock();
|
||||
return B->empty() ? CFGElement() : B->back();
|
||||
}
|
||||
|
||||
const Stmt* getTerminator() const {
|
||||
return getBlock()->getTerminator();
|
||||
}
|
||||
@ -183,14 +182,15 @@ class PreStmt : public StmtPoint {
|
||||
|
||||
class PostStmt : public StmtPoint {
|
||||
protected:
|
||||
PostStmt(const Stmt* S, Kind k, const LocationContext *L, const void *tag = 0)
|
||||
: StmtPoint(S, NULL, k, L, tag) {}
|
||||
|
||||
PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L,
|
||||
const void *tag =0)
|
||||
: StmtPoint(S, data, k, L, tag) {}
|
||||
|
||||
public:
|
||||
explicit PostStmt(const Stmt* S, Kind k,
|
||||
const LocationContext *L, const void *tag = 0)
|
||||
: StmtPoint(S, NULL, k, L, tag) {}
|
||||
|
||||
explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0)
|
||||
: StmtPoint(S, NULL, PostStmtKind, L, tag) {}
|
||||
|
||||
@ -313,19 +313,29 @@ class BlockEdge : public ProgramPoint {
|
||||
}
|
||||
};
|
||||
|
||||
class PostInitializer : public ProgramPoint {
|
||||
public:
|
||||
PostInitializer(const CXXCtorInitializer *I,
|
||||
const LocationContext *L)
|
||||
: ProgramPoint(I, PostInitializerKind, L) {}
|
||||
|
||||
static bool classof(const ProgramPoint *Location) {
|
||||
return Location->getKind() == PostInitializerKind;
|
||||
}
|
||||
};
|
||||
|
||||
class CallEnter : public StmtPoint {
|
||||
public:
|
||||
// L is caller's location context. AC is callee's AnalysisContext.
|
||||
CallEnter(const Stmt *S, const AnalysisContext *AC, const LocationContext *L)
|
||||
: StmtPoint(S, AC, CallEnterKind, L, 0) {}
|
||||
CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
|
||||
const LocationContext *callerCtx)
|
||||
: StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {}
|
||||
|
||||
const Stmt *getCallExpr() const {
|
||||
return static_cast<const Stmt *>(getData1());
|
||||
}
|
||||
|
||||
AnalysisContext *getCalleeContext() const {
|
||||
return const_cast<AnalysisContext *>(
|
||||
static_cast<const AnalysisContext *>(getData2()));
|
||||
const StackFrameContext *getCalleeContext() const {
|
||||
return static_cast<const StackFrameContext *>(getData2());
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint *Location) {
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
namespace clang {
|
||||
@ -155,7 +156,25 @@ class BumpVector {
|
||||
grow(C);
|
||||
goto Retry;
|
||||
}
|
||||
|
||||
|
||||
/// insert - Insert some number of copies of element into a position. Return
|
||||
/// iterator to position after last inserted copy.
|
||||
iterator insert(iterator I, size_t Cnt, const_reference E,
|
||||
BumpVectorContext &C) {
|
||||
assert (I >= Begin && I <= End && "Iterator out of bounds.");
|
||||
if (End + Cnt <= Capacity) {
|
||||
Retry:
|
||||
move_range_right(I, End, Cnt);
|
||||
construct_range(I, I + Cnt, E);
|
||||
End += Cnt;
|
||||
return I + Cnt;
|
||||
}
|
||||
ptrdiff_t D = I - Begin;
|
||||
grow(C, size() + Cnt);
|
||||
I = Begin + D;
|
||||
goto Retry;
|
||||
}
|
||||
|
||||
void reserve(BumpVectorContext &C, unsigned N) {
|
||||
if (unsigned(Capacity-Begin) < N)
|
||||
grow(C, N);
|
||||
@ -181,6 +200,14 @@ class BumpVector {
|
||||
E->~T();
|
||||
}
|
||||
}
|
||||
|
||||
void move_range_right(T *S, T *E, size_t D) {
|
||||
for (T *I = E + D - 1, *IL = S + D - 1; I != IL; --I) {
|
||||
--E;
|
||||
new (I) T(*E);
|
||||
E->~T();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Define this out-of-line to dissuade the C++ compiler from inlining it.
|
||||
|
@ -66,6 +66,8 @@ class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
|
||||
DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl?
|
||||
DISPATCH_CASE(CXXRecord)
|
||||
DISPATCH_CASE(Enum)
|
||||
DISPATCH_CASE(UsingDirective)
|
||||
DISPATCH_CASE(Using)
|
||||
default:
|
||||
assert(false && "Subtype of ScopedDecl not handled.");
|
||||
}
|
||||
@ -85,6 +87,8 @@ class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
|
||||
DEFAULT_DISPATCH(ObjCMethod)
|
||||
DEFAULT_DISPATCH(ObjCProtocol)
|
||||
DEFAULT_DISPATCH(ObjCCategory)
|
||||
DEFAULT_DISPATCH(UsingDirective)
|
||||
DEFAULT_DISPATCH(Using)
|
||||
|
||||
void VisitCXXRecordDecl(CXXRecordDecl *D) {
|
||||
static_cast<ImplClass*>(this)->VisitRecordDecl(D);
|
||||
|
@ -26,6 +26,11 @@ class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
|
||||
static_cast< ImplClass* >(this)->VisitChildren(S);
|
||||
}
|
||||
|
||||
void VisitCompoundStmt(CompoundStmt *S) {
|
||||
// Do nothing. Everything in a CompoundStmt is inlined
|
||||
// into the CFG.
|
||||
}
|
||||
|
||||
void VisitConditionVariableInit(Stmt *S) {
|
||||
assert(S == this->getCurrentBlkStmt());
|
||||
VarDecl *CondVar = 0;
|
||||
|
@ -80,6 +80,7 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
|
||||
DISPATCH_CASE(StmtExpr)
|
||||
DISPATCH_CASE(ConditionalOperator)
|
||||
DISPATCH_CASE(BinaryConditionalOperator)
|
||||
DISPATCH_CASE(ObjCForCollectionStmt)
|
||||
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
@ -102,6 +103,7 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
|
||||
DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
|
||||
DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
|
||||
DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator)
|
||||
|
||||
RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
|
||||
@ -155,7 +157,7 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
}
|
||||
}
|
||||
|
||||
for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
|
||||
for (Stmt::child_range I = S->children(); I; ++I)
|
||||
if (*I) static_cast<ImplClass*>(this)->Visit(*I);
|
||||
}
|
||||
};
|
||||
|
126
include/clang/Basic/ABI.h
Normal file
126
include/clang/Basic/ABI.h
Normal file
@ -0,0 +1,126 @@
|
||||
//===----- ABI.h - ABI related declarations ---------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// These enums/classes describe ABI related information about constructors,
|
||||
// destructors and thunks.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANG_BASIC_ABI_H
|
||||
#define CLANG_BASIC_ABI_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// CXXCtorType - C++ constructor types
|
||||
enum CXXCtorType {
|
||||
Ctor_Complete, // Complete object ctor
|
||||
Ctor_Base, // Base object ctor
|
||||
Ctor_CompleteAllocating // Complete object allocating ctor
|
||||
};
|
||||
|
||||
/// CXXDtorType - C++ destructor types
|
||||
enum CXXDtorType {
|
||||
Dtor_Deleting, // Deleting dtor
|
||||
Dtor_Complete, // Complete object dtor
|
||||
Dtor_Base // Base object dtor
|
||||
};
|
||||
|
||||
/// ReturnAdjustment - A return adjustment.
|
||||
struct ReturnAdjustment {
|
||||
/// NonVirtual - The non-virtual adjustment from the derived object to its
|
||||
/// nearest virtual base.
|
||||
int64_t NonVirtual;
|
||||
|
||||
/// VBaseOffsetOffset - The offset (in bytes), relative to the address point
|
||||
/// of the virtual base class offset.
|
||||
int64_t VBaseOffsetOffset;
|
||||
|
||||
ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
|
||||
|
||||
bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
|
||||
|
||||
friend bool operator==(const ReturnAdjustment &LHS,
|
||||
const ReturnAdjustment &RHS) {
|
||||
return LHS.NonVirtual == RHS.NonVirtual &&
|
||||
LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
|
||||
}
|
||||
|
||||
friend bool operator<(const ReturnAdjustment &LHS,
|
||||
const ReturnAdjustment &RHS) {
|
||||
if (LHS.NonVirtual < RHS.NonVirtual)
|
||||
return true;
|
||||
|
||||
return LHS.NonVirtual == RHS.NonVirtual &&
|
||||
LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset;
|
||||
}
|
||||
};
|
||||
|
||||
/// ThisAdjustment - A 'this' pointer adjustment.
|
||||
struct ThisAdjustment {
|
||||
/// NonVirtual - The non-virtual adjustment from the derived object to its
|
||||
/// nearest virtual base.
|
||||
int64_t NonVirtual;
|
||||
|
||||
/// VCallOffsetOffset - The offset (in bytes), relative to the address point,
|
||||
/// of the virtual call offset.
|
||||
int64_t VCallOffsetOffset;
|
||||
|
||||
ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { }
|
||||
|
||||
bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; }
|
||||
|
||||
friend bool operator==(const ThisAdjustment &LHS,
|
||||
const ThisAdjustment &RHS) {
|
||||
return LHS.NonVirtual == RHS.NonVirtual &&
|
||||
LHS.VCallOffsetOffset == RHS.VCallOffsetOffset;
|
||||
}
|
||||
|
||||
friend bool operator<(const ThisAdjustment &LHS,
|
||||
const ThisAdjustment &RHS) {
|
||||
if (LHS.NonVirtual < RHS.NonVirtual)
|
||||
return true;
|
||||
|
||||
return LHS.NonVirtual == RHS.NonVirtual &&
|
||||
LHS.VCallOffsetOffset < RHS.VCallOffsetOffset;
|
||||
}
|
||||
};
|
||||
|
||||
/// ThunkInfo - The 'this' pointer adjustment as well as an optional return
|
||||
/// adjustment for a thunk.
|
||||
struct ThunkInfo {
|
||||
/// This - The 'this' pointer adjustment.
|
||||
ThisAdjustment This;
|
||||
|
||||
/// Return - The return adjustment.
|
||||
ReturnAdjustment Return;
|
||||
|
||||
ThunkInfo() { }
|
||||
|
||||
ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
|
||||
: This(This), Return(Return) { }
|
||||
|
||||
friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
|
||||
return LHS.This == RHS.This && LHS.Return == RHS.Return;
|
||||
}
|
||||
|
||||
friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) {
|
||||
if (LHS.This < RHS.This)
|
||||
return true;
|
||||
|
||||
return LHS.This == RHS.This && LHS.Return < RHS.Return;
|
||||
}
|
||||
|
||||
bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // CLANG_BASIC_ABI_H
|
@ -89,171 +89,224 @@ class Attr {
|
||||
code AdditionalMembers = [{}];
|
||||
}
|
||||
|
||||
class InheritableAttr : Attr;
|
||||
|
||||
//
|
||||
// Attributes begin here
|
||||
//
|
||||
|
||||
def Alias : Attr {
|
||||
def Alias : InheritableAttr {
|
||||
let Spellings = ["alias"];
|
||||
let Args = [StringArgument<"Aliasee">];
|
||||
}
|
||||
|
||||
def Aligned : Attr {
|
||||
def Aligned : InheritableAttr {
|
||||
let Spellings = ["align", "aligned"];
|
||||
let Subjects = [NonBitField, NormalVar, Tag];
|
||||
let Args = [AlignedArgument<"Alignment">];
|
||||
let Namespaces = ["", "std"];
|
||||
}
|
||||
|
||||
def AlignMac68k : Attr {
|
||||
def AlignMac68k : InheritableAttr {
|
||||
let Spellings = [];
|
||||
}
|
||||
|
||||
def AlwaysInline : Attr {
|
||||
def AlwaysInline : InheritableAttr {
|
||||
let Spellings = ["always_inline"];
|
||||
}
|
||||
|
||||
def AnalyzerNoReturn : Attr {
|
||||
def AnalyzerNoReturn : InheritableAttr {
|
||||
let Spellings = ["analyzer_noreturn"];
|
||||
}
|
||||
|
||||
def Annotate : Attr {
|
||||
def Annotate : InheritableAttr {
|
||||
let Spellings = ["annotate"];
|
||||
let Args = [StringArgument<"Annotation">];
|
||||
}
|
||||
|
||||
def AsmLabel : Attr {
|
||||
def AsmLabel : InheritableAttr {
|
||||
let Spellings = [];
|
||||
let Args = [StringArgument<"Label">];
|
||||
}
|
||||
|
||||
def BaseCheck : Attr {
|
||||
let Spellings = ["base_check"];
|
||||
let Subjects = [CXXRecord];
|
||||
let Namespaces = ["", "std"];
|
||||
}
|
||||
|
||||
def Blocks : Attr {
|
||||
def Blocks : InheritableAttr {
|
||||
let Spellings = ["blocks"];
|
||||
let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>];
|
||||
}
|
||||
|
||||
def CarriesDependency : Attr {
|
||||
def CarriesDependency : InheritableAttr {
|
||||
let Spellings = ["carries_dependency"];
|
||||
let Subjects = [ParmVar, Function];
|
||||
let Namespaces = ["", "std"];
|
||||
}
|
||||
|
||||
def CDecl : Attr {
|
||||
def CDecl : InheritableAttr {
|
||||
let Spellings = ["cdecl", "__cdecl"];
|
||||
}
|
||||
|
||||
def CFReturnsRetained : Attr {
|
||||
def CFReturnsRetained : InheritableAttr {
|
||||
let Spellings = ["cf_returns_retained"];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def CFReturnsNotRetained : Attr {
|
||||
def CFReturnsNotRetained : InheritableAttr {
|
||||
let Spellings = ["cf_returns_not_retained"];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def Cleanup : Attr {
|
||||
def CFConsumed : InheritableAttr {
|
||||
let Spellings = ["cf_consumed"];
|
||||
let Subjects = [ParmVar];
|
||||
}
|
||||
|
||||
def Cleanup : InheritableAttr {
|
||||
let Spellings = ["cleanup"];
|
||||
let Args = [FunctionArgument<"FunctionDecl">];
|
||||
}
|
||||
|
||||
def Const : Attr {
|
||||
def Common : InheritableAttr {
|
||||
let Spellings = ["common"];
|
||||
}
|
||||
|
||||
def Const : InheritableAttr {
|
||||
let Spellings = ["const"];
|
||||
}
|
||||
|
||||
def Constructor : Attr {
|
||||
def Constructor : InheritableAttr {
|
||||
let Spellings = ["constructor"];
|
||||
let Args = [IntArgument<"Priority">];
|
||||
}
|
||||
|
||||
def Deprecated : Attr {
|
||||
let Spellings = ["deprecated"];
|
||||
def CUDAConstant : InheritableAttr {
|
||||
let Spellings = ["constant"];
|
||||
}
|
||||
|
||||
def Destructor : Attr {
|
||||
def CUDADevice : Attr {
|
||||
let Spellings = ["device"];
|
||||
}
|
||||
|
||||
def CUDAGlobal : InheritableAttr {
|
||||
let Spellings = ["global"];
|
||||
}
|
||||
|
||||
def CUDAHost : Attr {
|
||||
let Spellings = ["host"];
|
||||
}
|
||||
|
||||
def CUDALaunchBounds : InheritableAttr {
|
||||
let Spellings = ["launch_bounds"];
|
||||
let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>];
|
||||
}
|
||||
|
||||
def CUDAShared : InheritableAttr {
|
||||
let Spellings = ["shared"];
|
||||
}
|
||||
|
||||
def OpenCLKernel : Attr {
|
||||
let Spellings = ["opencl_kernel_function"];
|
||||
}
|
||||
|
||||
def Deprecated : InheritableAttr {
|
||||
let Spellings = ["deprecated"];
|
||||
let Args = [StringArgument<"Message">];
|
||||
}
|
||||
|
||||
def Destructor : InheritableAttr {
|
||||
let Spellings = ["destructor"];
|
||||
let Args = [IntArgument<"Priority">];
|
||||
}
|
||||
|
||||
def DLLExport : Attr {
|
||||
def DLLExport : InheritableAttr {
|
||||
let Spellings = ["dllexport"];
|
||||
}
|
||||
|
||||
def DLLImport : Attr {
|
||||
def DLLImport : InheritableAttr {
|
||||
let Spellings = ["dllimport"];
|
||||
}
|
||||
|
||||
def FastCall : Attr {
|
||||
def Explicit : InheritableAttr {
|
||||
let Spellings = [];
|
||||
}
|
||||
|
||||
def FastCall : InheritableAttr {
|
||||
let Spellings = ["fastcall", "__fastcall"];
|
||||
}
|
||||
|
||||
def Final : Attr {
|
||||
let Spellings = ["final"];
|
||||
let Subjects = [CXXRecord, CXXVirtualMethod];
|
||||
let Namespaces = ["", "std"];
|
||||
def Final : InheritableAttr {
|
||||
let Spellings = [];
|
||||
}
|
||||
|
||||
def Format : Attr {
|
||||
def Format : InheritableAttr {
|
||||
let Spellings = ["format"];
|
||||
let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,
|
||||
IntArgument<"FirstArg">];
|
||||
}
|
||||
|
||||
def FormatArg : Attr {
|
||||
def FormatArg : InheritableAttr {
|
||||
let Spellings = ["format_arg"];
|
||||
let Args = [IntArgument<"FormatIdx">];
|
||||
}
|
||||
|
||||
def GNUInline : Attr {
|
||||
def GNUInline : InheritableAttr {
|
||||
let Spellings = ["gnu_inline"];
|
||||
}
|
||||
|
||||
def Hiding : Attr {
|
||||
let Spellings = ["hiding"];
|
||||
let Subjects = [Field, CXXMethod];
|
||||
let Namespaces = ["", "std"];
|
||||
}
|
||||
|
||||
def IBAction : Attr {
|
||||
def IBAction : InheritableAttr {
|
||||
let Spellings = ["ibaction"];
|
||||
}
|
||||
|
||||
def IBOutlet : Attr {
|
||||
def IBOutlet : InheritableAttr {
|
||||
let Spellings = ["iboutlet"];
|
||||
}
|
||||
|
||||
def IBOutletCollection : Attr {
|
||||
def IBOutletCollection : InheritableAttr {
|
||||
let Spellings = ["iboutletcollection"];
|
||||
let Args = [TypeArgument<"Interface">];
|
||||
}
|
||||
|
||||
def Malloc : Attr {
|
||||
def Malloc : InheritableAttr {
|
||||
let Spellings = ["malloc"];
|
||||
}
|
||||
|
||||
def MaxFieldAlignment : Attr {
|
||||
def MaxFieldAlignment : InheritableAttr {
|
||||
let Spellings = [];
|
||||
let Args = [UnsignedArgument<"Alignment">];
|
||||
}
|
||||
|
||||
def MSP430Interrupt : Attr {
|
||||
def MayAlias : InheritableAttr {
|
||||
let Spellings = ["may_alias"];
|
||||
}
|
||||
|
||||
def MSP430Interrupt : InheritableAttr {
|
||||
let Spellings = [];
|
||||
let Args = [UnsignedArgument<"Number">];
|
||||
}
|
||||
|
||||
def NoDebug : Attr {
|
||||
def MBlazeInterruptHandler : InheritableAttr {
|
||||
let Spellings = [];
|
||||
}
|
||||
|
||||
def MBlazeSaveVolatiles : InheritableAttr {
|
||||
let Spellings = [];
|
||||
}
|
||||
|
||||
def Naked : InheritableAttr {
|
||||
let Spellings = ["naked"];
|
||||
}
|
||||
|
||||
def NoCommon : InheritableAttr {
|
||||
let Spellings = ["nocommon"];
|
||||
}
|
||||
|
||||
def NoDebug : InheritableAttr {
|
||||
let Spellings = ["nodebug"];
|
||||
}
|
||||
|
||||
def NoInline : Attr {
|
||||
def NoInline : InheritableAttr {
|
||||
let Spellings = ["noinline"];
|
||||
}
|
||||
|
||||
def NonNull : Attr {
|
||||
def NonNull : InheritableAttr {
|
||||
let Spellings = ["nonnull"];
|
||||
let Args = [VariadicUnsignedArgument<"Args">];
|
||||
let AdditionalMembers =
|
||||
@ -266,49 +319,64 @@ def NonNull : Attr {
|
||||
} }];
|
||||
}
|
||||
|
||||
def NoReturn : Attr {
|
||||
def NoReturn : InheritableAttr {
|
||||
let Spellings = ["noreturn"];
|
||||
// FIXME: Does GCC allow this on the function instead?
|
||||
let Subjects = [Function];
|
||||
let Namespaces = ["", "std"];
|
||||
}
|
||||
|
||||
def NoInstrumentFunction : Attr {
|
||||
def NoInstrumentFunction : InheritableAttr {
|
||||
let Spellings = ["no_instrument_function"];
|
||||
let Subjects = [Function];
|
||||
}
|
||||
|
||||
def NoThrow : Attr {
|
||||
def NoThrow : InheritableAttr {
|
||||
let Spellings = ["nothrow"];
|
||||
}
|
||||
|
||||
def NSReturnsRetained : Attr {
|
||||
def NSReturnsRetained : InheritableAttr {
|
||||
let Spellings = ["ns_returns_retained"];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def NSReturnsNotRetained : Attr {
|
||||
def NSReturnsNotRetained : InheritableAttr {
|
||||
let Spellings = ["ns_returns_not_retained"];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def ObjCException : Attr {
|
||||
def NSReturnsAutoreleased : InheritableAttr {
|
||||
let Spellings = ["ns_returns_autoreleased"];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def NSConsumesSelf : InheritableAttr {
|
||||
let Spellings = ["ns_consumes_self"];
|
||||
let Subjects = [ObjCMethod];
|
||||
}
|
||||
|
||||
def NSConsumed : InheritableAttr {
|
||||
let Spellings = ["ns_consumed"];
|
||||
let Subjects = [ParmVar];
|
||||
}
|
||||
|
||||
def ObjCException : InheritableAttr {
|
||||
let Spellings = ["objc_exception"];
|
||||
}
|
||||
|
||||
def ObjCNSObject : Attr {
|
||||
let Spellings = ["NSOjbect"];
|
||||
}
|
||||
|
||||
def Override : Attr {
|
||||
let Spellings = ["override"];
|
||||
let Subjects = [CXXVirtualMethod];
|
||||
let Namespaces = ["", "std"];
|
||||
def ObjCNSObject : InheritableAttr {
|
||||
let Spellings = ["NSObject"];
|
||||
}
|
||||
|
||||
def Overloadable : Attr {
|
||||
let Spellings = ["overloadable"];
|
||||
}
|
||||
|
||||
def Ownership : Attr {
|
||||
def Override : InheritableAttr {
|
||||
let Spellings = [];
|
||||
}
|
||||
|
||||
def Ownership : InheritableAttr {
|
||||
let Spellings = ["ownership_holds", "ownership_returns", "ownership_takes"];
|
||||
let Args = [EnumArgument<"OwnKind", "OwnershipKind",
|
||||
["ownership_holds", "ownership_returns", "ownership_takes"],
|
||||
@ -316,97 +384,104 @@ def Ownership : Attr {
|
||||
StringArgument<"Module">, VariadicUnsignedArgument<"Args">];
|
||||
}
|
||||
|
||||
def Packed : Attr {
|
||||
def Packed : InheritableAttr {
|
||||
let Spellings = ["packed"];
|
||||
}
|
||||
|
||||
def Pure : Attr {
|
||||
def Pure : InheritableAttr {
|
||||
let Spellings = ["pure"];
|
||||
}
|
||||
|
||||
def Regparm : Attr {
|
||||
def Regparm : InheritableAttr {
|
||||
let Spellings = ["regparm"];
|
||||
let Args = [UnsignedArgument<"NumParams">];
|
||||
}
|
||||
|
||||
def ReqdWorkGroupSize : Attr {
|
||||
def ReqdWorkGroupSize : InheritableAttr {
|
||||
let Spellings = ["reqd_work_group_size"];
|
||||
let Args = [UnsignedArgument<"XDim">, UnsignedArgument<"YDim">,
|
||||
UnsignedArgument<"ZDim">];
|
||||
}
|
||||
|
||||
def InitPriority : Attr {
|
||||
def InitPriority : InheritableAttr {
|
||||
let Spellings = ["init_priority"];
|
||||
let Args = [UnsignedArgument<"Priority">];
|
||||
}
|
||||
|
||||
def Section : Attr {
|
||||
def Section : InheritableAttr {
|
||||
let Spellings = ["section"];
|
||||
let Args = [StringArgument<"Name">];
|
||||
}
|
||||
|
||||
def Sentinel : Attr {
|
||||
def Sentinel : InheritableAttr {
|
||||
let Spellings = ["sentinel"];
|
||||
let Args = [DefaultIntArgument<"Sentinel", 0>,
|
||||
DefaultIntArgument<"NullPos", 0>];
|
||||
}
|
||||
|
||||
def StdCall : Attr {
|
||||
def StdCall : InheritableAttr {
|
||||
let Spellings = ["stdcall", "__stdcall"];
|
||||
}
|
||||
|
||||
def ThisCall : Attr {
|
||||
def ThisCall : InheritableAttr {
|
||||
let Spellings = ["thiscall", "__thiscall"];
|
||||
}
|
||||
|
||||
def Pascal : Attr {
|
||||
def Pascal : InheritableAttr {
|
||||
let Spellings = ["pascal", "__pascal"];
|
||||
}
|
||||
|
||||
def TransparentUnion : Attr {
|
||||
def TransparentUnion : InheritableAttr {
|
||||
let Spellings = ["transparent_union"];
|
||||
}
|
||||
|
||||
def Unavailable : Attr {
|
||||
def Unavailable : InheritableAttr {
|
||||
let Spellings = ["unavailable"];
|
||||
let Args = [StringArgument<"Message">];
|
||||
}
|
||||
|
||||
def Unused : Attr {
|
||||
def Unused : InheritableAttr {
|
||||
let Spellings = ["unused"];
|
||||
}
|
||||
|
||||
def Used : Attr {
|
||||
def Used : InheritableAttr {
|
||||
let Spellings = ["used"];
|
||||
}
|
||||
|
||||
def Visibility : Attr {
|
||||
def Uuid : InheritableAttr {
|
||||
let Spellings = ["uuid"];
|
||||
let Args = [StringArgument<"Guid">];
|
||||
let Subjects = [CXXRecord];
|
||||
}
|
||||
|
||||
def Visibility : InheritableAttr {
|
||||
let Spellings = ["visibility"];
|
||||
let Args = [EnumArgument<"Visibility", "VisibilityType",
|
||||
["default", "hidden", "internal", "protected"],
|
||||
["Default", "Hidden", "Hidden", "Protected"]>];
|
||||
}
|
||||
|
||||
def VecReturn : Attr {
|
||||
def VecReturn : InheritableAttr {
|
||||
let Spellings = ["vecreturn"];
|
||||
let Subjects = [CXXRecord];
|
||||
}
|
||||
|
||||
def WarnUnusedResult : Attr {
|
||||
def WarnUnusedResult : InheritableAttr {
|
||||
let Spellings = ["warn_unused_result"];
|
||||
}
|
||||
|
||||
def Weak : Attr {
|
||||
def Weak : InheritableAttr {
|
||||
let Spellings = ["weak"];
|
||||
}
|
||||
|
||||
def WeakImport : Attr {
|
||||
def WeakImport : InheritableAttr {
|
||||
let Spellings = ["weak_import"];
|
||||
}
|
||||
|
||||
def WeakRef : Attr {
|
||||
def WeakRef : InheritableAttr {
|
||||
let Spellings = ["weakref"];
|
||||
}
|
||||
|
||||
def X86ForceAlignArgPointer : Attr {
|
||||
def X86ForceAlignArgPointer : InheritableAttr {
|
||||
let Spellings = [];
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ namespace attr {
|
||||
// Kind - This is a list of all the recognized kinds of attributes.
|
||||
enum Kind {
|
||||
#define ATTR(X) X,
|
||||
#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X,
|
||||
#include "clang/Basic/AttrList.inc"
|
||||
NUM_ATTRS
|
||||
};
|
||||
|
@ -29,6 +29,8 @@
|
||||
// d -> double
|
||||
// z -> size_t
|
||||
// F -> constant CFString
|
||||
// G -> id
|
||||
// H -> SEL
|
||||
// a -> __builtin_va_list
|
||||
// A -> "reference" to __builtin_va_list
|
||||
// V -> Vector, following num elements and a base type.
|
||||
@ -38,12 +40,13 @@
|
||||
// SJ -> sigjmp_buf
|
||||
// . -> "...". This may only occur at the end of the function list.
|
||||
//
|
||||
// Types maybe prefixed with the following modifiers:
|
||||
// Types may be prefixed with the following modifiers:
|
||||
// L -> long (e.g. Li for 'long int')
|
||||
// LL -> long long
|
||||
// LLL -> __int128_t (e.g. LLLi)
|
||||
// S -> signed
|
||||
// U -> unsigned
|
||||
// I -> Required to constant fold to an integer constant expression.
|
||||
//
|
||||
// Types may be postfixed with the following modifiers:
|
||||
// * -> pointer (optionally followed by an address space number)
|
||||
@ -75,7 +78,7 @@
|
||||
// FIXME: gcc has nonnull
|
||||
|
||||
#if defined(BUILTIN) && !defined(LIBBUILTIN)
|
||||
# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) BUILTIN(ID, TYPE, ATTRS)
|
||||
# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
|
||||
// Standard libc/libm functions:
|
||||
@ -124,12 +127,24 @@ BUILTIN(__builtin_powl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_acos , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_acosf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_acosl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_acosh , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_acoshf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_acoshl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_asin , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_asinf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_asinl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_asinh , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_asinhf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_asinhl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_atan , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_atanf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_atanl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_atanh , "dd", "Fnc")
|
||||
BUILTIN(__builtin_atanhf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_atanhl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_cbrt , "dd", "Fnc")
|
||||
BUILTIN(__builtin_cbrtf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_cbrtl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_ceil , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_ceilf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_ceill, "LdLd", "Fnc")
|
||||
@ -139,21 +154,99 @@ BUILTIN(__builtin_cosh , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_coshf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_coshl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_cosl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_erf , "dd", "Fnc")
|
||||
BUILTIN(__builtin_erff, "ff", "Fnc")
|
||||
BUILTIN(__builtin_erfl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_erfc , "dd", "Fnc")
|
||||
BUILTIN(__builtin_erfcf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_erfcl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_exp , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_expf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_expl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_exp2 , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_exp2f, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_exp2l, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_expm1 , "dd", "Fnc")
|
||||
BUILTIN(__builtin_expm1f, "ff", "Fnc")
|
||||
BUILTIN(__builtin_expm1l, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_fdim, "ddd", "Fnc")
|
||||
BUILTIN(__builtin_fdimf, "fff", "Fnc")
|
||||
BUILTIN(__builtin_fdiml, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_floor , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_floorf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_floorl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_fma, "dddd", "Fnc")
|
||||
BUILTIN(__builtin_fmaf, "ffff", "Fnc")
|
||||
BUILTIN(__builtin_fmal, "LdLdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_fmax, "ddd", "Fnc")
|
||||
BUILTIN(__builtin_fmaxf, "fff", "Fnc")
|
||||
BUILTIN(__builtin_fmaxl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_fmin, "ddd", "Fnc")
|
||||
BUILTIN(__builtin_fminf, "fff", "Fnc")
|
||||
BUILTIN(__builtin_fminl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_hypot , "ddd" , "Fnc")
|
||||
BUILTIN(__builtin_hypotf, "fff" , "Fnc")
|
||||
BUILTIN(__builtin_hypotl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_ilogb , "id", "Fnc")
|
||||
BUILTIN(__builtin_ilogbf, "if", "Fnc")
|
||||
BUILTIN(__builtin_ilogbl, "iLd", "Fnc")
|
||||
BUILTIN(__builtin_lgamma , "dd", "Fnc")
|
||||
BUILTIN(__builtin_lgammaf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_lgammal, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_llrint, "LLid", "Fnc")
|
||||
BUILTIN(__builtin_llrintf, "LLif", "Fnc")
|
||||
BUILTIN(__builtin_llrintl, "LLiLd", "Fnc")
|
||||
BUILTIN(__builtin_llround , "LLid", "Fnc")
|
||||
BUILTIN(__builtin_llroundf, "LLif", "Fnc")
|
||||
BUILTIN(__builtin_llroundl, "LLiLd", "Fnc")
|
||||
BUILTIN(__builtin_log , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_log10 , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_log10f, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_log10l, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_log1p , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_log1pf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_log1pl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_log2, "dd" , "Fnc")
|
||||
BUILTIN(__builtin_log2f, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_log2l, "LdLd" , "Fnc")
|
||||
BUILTIN(__builtin_logb , "dd", "Fnc")
|
||||
BUILTIN(__builtin_logbf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_logbl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_logf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_logl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_lrint , "Lid", "Fnc")
|
||||
BUILTIN(__builtin_lrintf, "Lif", "Fnc")
|
||||
BUILTIN(__builtin_lrintl, "LiLd", "Fnc")
|
||||
BUILTIN(__builtin_lround , "Lid", "Fnc")
|
||||
BUILTIN(__builtin_lroundf, "Lif", "Fnc")
|
||||
BUILTIN(__builtin_lroundl, "LiLd", "Fnc")
|
||||
BUILTIN(__builtin_nearbyint , "dd", "Fnc")
|
||||
BUILTIN(__builtin_nearbyintf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_nearbyintl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_nextafter , "ddd", "Fnc")
|
||||
BUILTIN(__builtin_nextafterf, "fff", "Fnc")
|
||||
BUILTIN(__builtin_nextafterl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_nexttoward , "ddd", "Fnc")
|
||||
BUILTIN(__builtin_nexttowardf, "fff", "Fnc")
|
||||
BUILTIN(__builtin_nexttowardl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_remainder , "ddd", "Fnc")
|
||||
BUILTIN(__builtin_remainderf, "fff", "Fnc")
|
||||
BUILTIN(__builtin_remainderl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_remquo , "dddi*", "Fnc")
|
||||
BUILTIN(__builtin_remquof, "fffi*", "Fnc")
|
||||
BUILTIN(__builtin_remquol, "LdLdLdi*", "Fnc")
|
||||
BUILTIN(__builtin_rint , "dd", "Fnc")
|
||||
BUILTIN(__builtin_rintf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_rintl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_round, "dd" , "Fnc")
|
||||
BUILTIN(__builtin_roundf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_roundl, "LdLd" , "Fnc")
|
||||
BUILTIN(__builtin_scalbln , "ddLi", "Fnc")
|
||||
BUILTIN(__builtin_scalblnf, "ffLi", "Fnc")
|
||||
BUILTIN(__builtin_scalblnl, "LdLdLi", "Fnc")
|
||||
BUILTIN(__builtin_scalbn , "ddi", "Fnc")
|
||||
BUILTIN(__builtin_scalbnf, "ffi", "Fnc")
|
||||
BUILTIN(__builtin_scalbnl, "LdLdi", "Fnc")
|
||||
BUILTIN(__builtin_sin , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_sinf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_sinh , "dd" , "Fnc")
|
||||
@ -169,6 +262,12 @@ BUILTIN(__builtin_tanh , "dd" , "Fnc")
|
||||
BUILTIN(__builtin_tanhf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_tanhl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_tanl, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_tgamma , "dd", "Fnc")
|
||||
BUILTIN(__builtin_tgammaf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_tgammal, "LdLd", "Fnc")
|
||||
BUILTIN(__builtin_trunc , "dd", "Fnc")
|
||||
BUILTIN(__builtin_truncf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_truncl, "LdLd", "Fnc")
|
||||
|
||||
// C99 complex builtins
|
||||
BUILTIN(__builtin_cabs, "dXd", "Fnc")
|
||||
@ -176,15 +275,24 @@ BUILTIN(__builtin_cabsf, "fXf", "Fnc")
|
||||
BUILTIN(__builtin_cabsl, "LdXLd", "Fnc")
|
||||
BUILTIN(__builtin_cacos, "XdXd", "Fnc")
|
||||
BUILTIN(__builtin_cacosf, "XfXf", "Fnc")
|
||||
BUILTIN(__builtin_cacosh, "XdXd", "Fnc")
|
||||
BUILTIN(__builtin_cacoshf, "XfXf", "Fnc")
|
||||
BUILTIN(__builtin_cacoshl, "XLdXLd", "Fnc")
|
||||
BUILTIN(__builtin_cacosl, "XLdXLd", "Fnc")
|
||||
BUILTIN(__builtin_carg, "dXd", "Fnc")
|
||||
BUILTIN(__builtin_cargf, "fXf", "Fnc")
|
||||
BUILTIN(__builtin_cargl, "LdXLd", "Fnc")
|
||||
BUILTIN(__builtin_casin, "XdXd", "Fnc")
|
||||
BUILTIN(__builtin_casinf, "XfXf", "Fnc")
|
||||
BUILTIN(__builtin_casinh, "XdXd", "Fnc")
|
||||
BUILTIN(__builtin_casinhf, "XfXf", "Fnc")
|
||||
BUILTIN(__builtin_casinhl, "XLdXLd", "Fnc")
|
||||
BUILTIN(__builtin_casinl, "XLdXLd", "Fnc")
|
||||
BUILTIN(__builtin_catan, "XdXd", "Fnc")
|
||||
BUILTIN(__builtin_catanf, "XfXf", "Fnc")
|
||||
BUILTIN(__builtin_catanh, "XdXd", "Fnc")
|
||||
BUILTIN(__builtin_catanhf, "XfXf", "Fnc")
|
||||
BUILTIN(__builtin_catanhl, "XLdXLd", "Fnc")
|
||||
BUILTIN(__builtin_catanl, "XLdXLd", "Fnc")
|
||||
BUILTIN(__builtin_ccos, "XdXd", "Fnc")
|
||||
BUILTIN(__builtin_ccosf, "XfXf", "Fnc")
|
||||
@ -275,7 +383,7 @@ BUILTIN(__builtin_bswap32, "UiUi", "nc")
|
||||
BUILTIN(__builtin_bswap64, "ULLiULLi", "nc")
|
||||
|
||||
// Random GCC builtins
|
||||
BUILTIN(__builtin_constant_p, "Us.", "nc")
|
||||
BUILTIN(__builtin_constant_p, "i.", "nc")
|
||||
BUILTIN(__builtin_classify_type, "i.", "nc")
|
||||
BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc")
|
||||
BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc")
|
||||
@ -313,14 +421,14 @@ BUILTIN(__builtin_strpbrk, "c*cC*cC*", "nF")
|
||||
BUILTIN(__builtin_strrchr, "c*cC*i", "nF")
|
||||
BUILTIN(__builtin_strspn, "zcC*cC*", "nF")
|
||||
BUILTIN(__builtin_strstr, "c*cC*cC*", "nF")
|
||||
BUILTIN(__builtin_return_address, "v*Ui", "n")
|
||||
BUILTIN(__builtin_return_address, "v*IUi", "n")
|
||||
BUILTIN(__builtin_extract_return_addr, "v*v*", "n")
|
||||
BUILTIN(__builtin_frame_address, "v*Ui", "n")
|
||||
BUILTIN(__builtin_frame_address, "v*IUi", "n")
|
||||
BUILTIN(__builtin_flt_rounds, "i", "nc")
|
||||
BUILTIN(__builtin_setjmp, "iv**", "")
|
||||
BUILTIN(__builtin_longjmp, "vv**i", "r")
|
||||
BUILTIN(__builtin_unwind_init, "v", "")
|
||||
BUILTIN(__builtin_eh_return_data_regno, "ii", "nc")
|
||||
BUILTIN(__builtin_eh_return_data_regno, "iIi", "nc")
|
||||
BUILTIN(__builtin_snprintf, "ic*zcC*.", "nFp:2:")
|
||||
BUILTIN(__builtin_vsprintf, "ic*cC*a", "nFP:1:")
|
||||
BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:")
|
||||
@ -485,92 +593,135 @@ BUILTIN(__builtin_abort, "v", "Fnr")
|
||||
BUILTIN(__builtin_index, "c*cC*i", "Fn")
|
||||
BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
|
||||
|
||||
|
||||
// Microsoft builtins.
|
||||
BUILTIN(__assume, "vb", "n")
|
||||
BUILTIN(__noop, "v.", "n")
|
||||
|
||||
// C99 library functions
|
||||
// C99 stdlib.h
|
||||
LIBBUILTIN(abort, "v", "fr", "stdlib.h")
|
||||
LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h")
|
||||
LIBBUILTIN(exit, "vi", "fr", "stdlib.h")
|
||||
LIBBUILTIN(_Exit, "vi", "fr", "stdlib.h")
|
||||
LIBBUILTIN(malloc, "v*z", "f", "stdlib.h")
|
||||
LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h")
|
||||
LIBBUILTIN(abort, "v", "fr", "stdlib.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(_Exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(malloc, "v*z", "f", "stdlib.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h", ALL_LANGUAGES)
|
||||
// C99 string.h
|
||||
LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h")
|
||||
LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h")
|
||||
LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h")
|
||||
LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h")
|
||||
LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h")
|
||||
LIBBUILTIN(memchr, "v*vC*iz", "f", "string.h")
|
||||
LIBBUILTIN(strchr, "c*cC*i", "f", "string.h")
|
||||
LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h")
|
||||
LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strtok, "c*c*cC*", "f", "string.h")
|
||||
LIBBUILTIN(memset, "v*v*iz", "f", "string.h")
|
||||
LIBBUILTIN(strerror, "c*i", "f", "string.h")
|
||||
LIBBUILTIN(strlen, "zcC*", "f", "string.h")
|
||||
LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(memchr, "v*vC*iz", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strtok, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(memset, "v*v*iz", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strerror, "c*i", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strlen, "zcC*", "f", "string.h", ALL_LANGUAGES)
|
||||
// C99 stdio.h
|
||||
LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h")
|
||||
LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h")
|
||||
LIBBUILTIN(snprintf, "ic*zcC*.", "fp:2:", "stdio.h")
|
||||
LIBBUILTIN(sprintf, "ic*cC*.", "fp:1:", "stdio.h")
|
||||
LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h")
|
||||
LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h")
|
||||
LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h")
|
||||
LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h")
|
||||
LIBBUILTIN(scanf, "icC*.", "fs:0:", "stdio.h")
|
||||
LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(snprintf, "ic*zcC*.", "fp:2:", "stdio.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sprintf, "ic*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(scanf, "icC*.", "fs:0:", "stdio.h", ALL_LANGUAGES)
|
||||
// C99
|
||||
LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h")
|
||||
LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
|
||||
|
||||
// Non-C library functions
|
||||
// FIXME: Non-C-standard stuff shouldn't be builtins in non-GNU mode!
|
||||
LIBBUILTIN(alloca, "v*z", "f", "stdlib.h")
|
||||
LIBBUILTIN(alloca, "v*z", "f", "stdlib.h", ALL_LANGUAGES)
|
||||
// POSIX string.h
|
||||
LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h")
|
||||
LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h")
|
||||
LIBBUILTIN(strdup, "c*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strndup, "c*cC*z", "f", "string.h")
|
||||
LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strdup, "c*cC*", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_LANGUAGES)
|
||||
// POSIX strings.h
|
||||
LIBBUILTIN(index, "c*cC*i", "f", "strings.h")
|
||||
LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h")
|
||||
LIBBUILTIN(bzero, "vv*z", "f", "strings.h")
|
||||
LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES)
|
||||
// POSIX unistd.h
|
||||
LIBBUILTIN(_exit, "vi", "fr", "unistd.h")
|
||||
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES)
|
||||
// POSIX setjmp.h
|
||||
LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h")
|
||||
LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h")
|
||||
LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_LANGUAGES)
|
||||
// id objc_msgSend(id, SEL, ...)
|
||||
LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG)
|
||||
|
||||
// long double objc_msgSend_fpret(id self, SEL op, ...)
|
||||
LIBBUILTIN(objc_msgSend_fpret, "LdGH.", "f", "objc/message.h", OBJC_LANG)
|
||||
// id objc_msgSend_stret (id, SEL, ...)
|
||||
LIBBUILTIN(objc_msgSend_stret, "GGH.", "f", "objc/message.h", OBJC_LANG)
|
||||
// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
|
||||
LIBBUILTIN(objc_msgSendSuper, "Gv*H.", "f", "objc/message.h", OBJC_LANG)
|
||||
// void objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...)
|
||||
LIBBUILTIN(objc_msgSendSuper_stret, "vv*H.", "f", "objc/message.h", OBJC_LANG)
|
||||
// id objc_getClass(const char *name)
|
||||
LIBBUILTIN(objc_getClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG)
|
||||
// id objc_getMetaClass(const char *name)
|
||||
LIBBUILTIN(objc_getMetaClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG)
|
||||
// void objc_enumerationMutation(id)
|
||||
LIBBUILTIN(objc_enumerationMutation, "vG", "f", "objc/runtime.h", OBJC_LANG)
|
||||
|
||||
// id objc_read_weak(id *location)
|
||||
LIBBUILTIN(objc_read_weak, "GG*", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
// id objc_assign_weak(id value, id *location)
|
||||
LIBBUILTIN(objc_assign_weak, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
// id objc_assign_ivar(id value, id dest, ptrdiff_t offset)
|
||||
// FIXME. Darwin has ptrdiff_t typedef'ed to int.
|
||||
LIBBUILTIN(objc_assign_ivar, "GGGi", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
// id objc_assign_global(id val, id *dest)
|
||||
LIBBUILTIN(objc_assign_global, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
// id objc_assign_strongCast(id val, id *dest
|
||||
LIBBUILTIN(objc_assign_strongCast, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
|
||||
// id objc_exception_extract(void *localExceptionData)
|
||||
LIBBUILTIN(objc_exception_extract, "Gv*", "f", "/objc/objc-exception.h", OBJC_LANG)
|
||||
// void objc_exception_try_enter(void *localExceptionData)
|
||||
LIBBUILTIN(objc_exception_try_enter, "vv*", "f", "/objc/objc-exception.h", OBJC_LANG)
|
||||
// void objc_exception_try_exit(void *localExceptionData)
|
||||
LIBBUILTIN(objc_exception_try_exit, "vv*", "f", "/objc/objc-exception.h", OBJC_LANG)
|
||||
// int objc_exception_match(Class exceptionClass, id exception)
|
||||
LIBBUILTIN(objc_exception_match, "iGG", "f", "/objc/objc-exception.h", OBJC_LANG)
|
||||
// void objc_exception_throw(id exception)
|
||||
LIBBUILTIN(objc_exception_throw, "vG", "f", "/objc/objc-exception.h", OBJC_LANG)
|
||||
|
||||
// int objc_sync_enter(id obj)
|
||||
LIBBUILTIN(objc_sync_enter, "iG", "f", "/objc/objc-sync.h", OBJC_LANG)
|
||||
// int objc_sync_exit(id obj)
|
||||
LIBBUILTIN(objc_sync_exit, "iG", "f", "/objc/objc-sync.h", OBJC_LANG)
|
||||
|
||||
// FIXME: This type isn't very correct, it should be
|
||||
// id objc_msgSend(id, SEL)
|
||||
// but we need new type letters for that.
|
||||
LIBBUILTIN(objc_msgSend, "v*.", "f", "objc/message.h")
|
||||
BUILTIN(__builtin_objc_memmove_collectable, "v*v*vC*z", "nF")
|
||||
|
||||
// Builtin math library functions
|
||||
LIBBUILTIN(pow, "ddd", "fe", "math.h")
|
||||
LIBBUILTIN(powl, "LdLdLd", "fe", "math.h")
|
||||
LIBBUILTIN(powf, "fff", "fe", "math.h")
|
||||
LIBBUILTIN(pow, "ddd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(powl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(powf, "fff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(sqrt, "dd", "fe", "math.h")
|
||||
LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h")
|
||||
LIBBUILTIN(sqrtf, "ff", "fe", "math.h")
|
||||
LIBBUILTIN(sqrt, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sqrtf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(sin, "dd", "fe", "math.h")
|
||||
LIBBUILTIN(sinl, "LdLd", "fe", "math.h")
|
||||
LIBBUILTIN(sinf, "ff", "fe", "math.h")
|
||||
LIBBUILTIN(sin, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sinl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sinf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(cos, "dd", "fe", "math.h")
|
||||
LIBBUILTIN(cosl, "LdLd", "fe", "math.h")
|
||||
LIBBUILTIN(cosf, "ff", "fe", "math.h")
|
||||
LIBBUILTIN(cos, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(cosl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(cosf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
// Blocks runtime Builtin math library functions
|
||||
LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h")
|
||||
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h")
|
||||
LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
|
||||
// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
|
||||
|
||||
#undef BUILTIN
|
||||
|
@ -30,7 +30,15 @@ namespace clang {
|
||||
class IdentifierTable;
|
||||
class ASTContext;
|
||||
class QualType;
|
||||
|
||||
class LangOptions;
|
||||
|
||||
enum LanguageID {
|
||||
C_LANG = 0x1, // builtin for c only.
|
||||
CXX_LANG = 0x2, // builtin for cplusplus only.
|
||||
OBJC_LANG = 0x4, // builtin for objective-c and objective-c++
|
||||
ALL_LANGUAGES = (C_LANG|CXX_LANG|OBJC_LANG) //builtin is for all languages.
|
||||
};
|
||||
|
||||
namespace Builtin {
|
||||
enum ID {
|
||||
NotBuiltin = 0, // This is not a builtin function.
|
||||
@ -41,6 +49,7 @@ enum ID {
|
||||
|
||||
struct Info {
|
||||
const char *Name, *Type, *Attributes, *HeaderName;
|
||||
LanguageID builtin_lang;
|
||||
bool Suppressed;
|
||||
|
||||
bool operator==(const Info &RHS) const {
|
||||
@ -62,7 +71,7 @@ class Context {
|
||||
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
|
||||
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
|
||||
/// such.
|
||||
void InitializeBuiltins(IdentifierTable &Table, bool NoBuiltins = false);
|
||||
void InitializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts);
|
||||
|
||||
/// \brief Popular the vector with the names of all of the builtins.
|
||||
void GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
|
||||
@ -108,6 +117,10 @@ class Context {
|
||||
return strchr(GetRecord(ID).Attributes, 'f') != 0;
|
||||
}
|
||||
|
||||
/// \brief Completely forget that the given ID was ever considered a builtin,
|
||||
/// e.g., because the user provided a conflicting signature.
|
||||
void ForgetBuiltin(unsigned ID, IdentifierTable &Table);
|
||||
|
||||
/// \brief If this is a library function that comes from a specific
|
||||
/// header, retrieve that header name.
|
||||
const char *getHeaderName(unsigned ID) const {
|
||||
@ -124,12 +137,6 @@ class Context {
|
||||
/// argument and whether this function as a va_list argument.
|
||||
bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);
|
||||
|
||||
/// hasVAListUse - Return true of the specified builtin uses __builtin_va_list
|
||||
/// as an operand or return type.
|
||||
bool hasVAListUse(unsigned ID) const {
|
||||
return strpbrk(GetRecord(ID).Type, "Aa") != 0;
|
||||
}
|
||||
|
||||
/// isConstWithoutErrno - Return true if this function has no side
|
||||
/// effects and doesn't read memory, except for possibly errno. Such
|
||||
/// functions can be const when the MathErrno lang option is
|
||||
|
@ -50,25 +50,25 @@ BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fi", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_dss, "vUi", "")
|
||||
BUILTIN(__builtin_altivec_dssall, "v", "")
|
||||
BUILTIN(__builtin_altivec_dst, "vv*iUi", "")
|
||||
BUILTIN(__builtin_altivec_dstt, "vv*iUi", "")
|
||||
BUILTIN(__builtin_altivec_dstst, "vv*iUi", "")
|
||||
BUILTIN(__builtin_altivec_dststt, "vv*iUi", "")
|
||||
BUILTIN(__builtin_altivec_dst, "vvC*iUi", "")
|
||||
BUILTIN(__builtin_altivec_dstt, "vvC*iUi", "")
|
||||
BUILTIN(__builtin_altivec_dstst, "vvC*iUi", "")
|
||||
BUILTIN(__builtin_altivec_dststt, "vvC*iUi", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vexptefp, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vrfim, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_lvx, "V4iiv*", "")
|
||||
BUILTIN(__builtin_altivec_lvxl, "V4iiv*", "")
|
||||
BUILTIN(__builtin_altivec_lvebx, "V16civ*", "")
|
||||
BUILTIN(__builtin_altivec_lvehx, "V8siv*", "")
|
||||
BUILTIN(__builtin_altivec_lvewx, "V4iiv*", "")
|
||||
BUILTIN(__builtin_altivec_lvx, "V4iivC*", "")
|
||||
BUILTIN(__builtin_altivec_lvxl, "V4iivC*", "")
|
||||
BUILTIN(__builtin_altivec_lvebx, "V16civC*", "")
|
||||
BUILTIN(__builtin_altivec_lvehx, "V8sivC*", "")
|
||||
BUILTIN(__builtin_altivec_lvewx, "V4iivC*", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vlogefp, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_lvsl, "V16cUcv*", "")
|
||||
BUILTIN(__builtin_altivec_lvsr, "V16cUcv*", "")
|
||||
BUILTIN(__builtin_altivec_lvsl, "V16cUcvC*", "")
|
||||
BUILTIN(__builtin_altivec_lvsr, "V16cUcvC*", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vmaddfp, "V4fV4fV4fV4f", "")
|
||||
BUILTIN(__builtin_altivec_vmhaddshs, "V8sV8sV8sV8s", "")
|
||||
|
@ -25,11 +25,16 @@
|
||||
// FIXME: Are these nothrow/const?
|
||||
|
||||
// MMX
|
||||
//
|
||||
// FIXME: All MMX instructions will be generated via builtins. Any MMX vector
|
||||
// types (<1 x i64>, <2 x i32>, etc.) that aren't used by these builtins will be
|
||||
// expanded by the back-end.
|
||||
BUILTIN(__builtin_ia32_emms, "v", "")
|
||||
BUILTIN(__builtin_ia32_femms, "v", "")
|
||||
BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "")
|
||||
@ -37,6 +42,7 @@ BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "")
|
||||
@ -76,6 +82,7 @@ BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pshufw, "V4sV4sIc", "")
|
||||
BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "")
|
||||
@ -91,7 +98,7 @@ BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "")
|
||||
BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "")
|
||||
BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "")
|
||||
BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cc", "") // FIXME: Correct type?
|
||||
BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cIc", "")
|
||||
BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "")
|
||||
BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "")
|
||||
BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "")
|
||||
@ -249,8 +256,8 @@ BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psrlw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psrld128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pslldqi128, "V2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_psrldqi128, "V2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_pslldqi128, "V2LLiV2LLiIi", "")
|
||||
BUILTIN(__builtin_ia32_psrldqi128, "V2LLiV2LLiIi", "")
|
||||
BUILTIN(__builtin_ia32_psrlq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_psllw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pslld128, "V4iV4iV4i", "")
|
||||
@ -267,7 +274,7 @@ BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "")
|
||||
BUILTIN(__builtin_ia32_mwait, "vUiUi", "")
|
||||
BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "")
|
||||
BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cc", "") // FIXME: Correct type?
|
||||
BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cIc", "") // FIXME: Correct type?
|
||||
BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "")
|
||||
|
@ -15,6 +15,7 @@ def Named : Decl<1>;
|
||||
def Namespace : DDecl<Named>, DeclContext;
|
||||
def UsingDirective : DDecl<Named>;
|
||||
def NamespaceAlias : DDecl<Named>;
|
||||
def Label : DDecl<Named>;
|
||||
def Type : DDecl<Named, 1>;
|
||||
def Typedef : DDecl<Type>;
|
||||
def UnresolvedUsingTypename : DDecl<Type>;
|
||||
@ -29,6 +30,7 @@ def Named : Decl<1>;
|
||||
def Value : DDecl<Named, 1>;
|
||||
def EnumConstant : DDecl<Value>;
|
||||
def UnresolvedUsingValue : DDecl<Value>;
|
||||
def IndirectField : DDecl<Value>;
|
||||
def Declarator : DDecl<Value, 1>;
|
||||
def Function : DDecl<Declarator>, DeclContext;
|
||||
def CXXMethod : DDecl<Function>;
|
||||
@ -41,7 +43,7 @@ def Named : Decl<1>;
|
||||
def Var : DDecl<Declarator>;
|
||||
def ImplicitParam : DDecl<Var>;
|
||||
def ParmVar : DDecl<Var>;
|
||||
def NonTypeTemplateParm : DDecl<Var>;
|
||||
def NonTypeTemplateParm : DDecl<Declarator>;
|
||||
def Template : DDecl<Named, 1>;
|
||||
def RedeclarableTemplate : DDecl<Template, 1>;
|
||||
def FunctionTemplate : DDecl<RedeclarableTemplate>;
|
||||
|
@ -14,76 +14,24 @@
|
||||
#ifndef LLVM_CLANG_DIAGNOSTIC_H
|
||||
#define LLVM_CLANG_DIAGNOSTIC_H
|
||||
|
||||
#include "clang/Basic/DiagnosticIDs.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
template <typename T> class SmallVectorImpl;
|
||||
}
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
namespace clang {
|
||||
class DeclContext;
|
||||
class DiagnosticBuilder;
|
||||
class DiagnosticClient;
|
||||
class FileManager;
|
||||
class DiagnosticBuilder;
|
||||
class IdentifierInfo;
|
||||
class DeclContext;
|
||||
class LangOptions;
|
||||
class PartialDiagnostic;
|
||||
class Preprocessor;
|
||||
|
||||
// Import the diagnostic enums themselves.
|
||||
namespace diag {
|
||||
// Start position for diagnostics.
|
||||
enum {
|
||||
DIAG_START_DRIVER = 300,
|
||||
DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
|
||||
DIAG_START_LEX = DIAG_START_FRONTEND + 100,
|
||||
DIAG_START_PARSE = DIAG_START_LEX + 300,
|
||||
DIAG_START_AST = DIAG_START_PARSE + 300,
|
||||
DIAG_START_SEMA = DIAG_START_AST + 100,
|
||||
DIAG_START_ANALYSIS = DIAG_START_SEMA + 1500,
|
||||
DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
|
||||
};
|
||||
|
||||
class CustomDiagInfo;
|
||||
|
||||
/// diag::kind - All of the diagnostics that can be emitted by the frontend.
|
||||
typedef unsigned kind;
|
||||
|
||||
// Get typedefs for common diagnostics.
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM,
|
||||
#include "clang/Basic/DiagnosticCommonKinds.inc"
|
||||
NUM_BUILTIN_COMMON_DIAGNOSTICS
|
||||
#undef DIAG
|
||||
};
|
||||
|
||||
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
||||
/// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR
|
||||
/// (emit as an error). It allows clients to map errors to
|
||||
/// MAP_ERROR/MAP_DEFAULT or MAP_FATAL (stop emitting diagnostics after this
|
||||
/// one).
|
||||
enum Mapping {
|
||||
// NOTE: 0 means "uncomputed".
|
||||
MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it.
|
||||
MAP_WARNING = 2, //< Map this diagnostic to a warning.
|
||||
MAP_ERROR = 3, //< Map this diagnostic to an error.
|
||||
MAP_FATAL = 4, //< Map this diagnostic to a fatal error.
|
||||
|
||||
/// Map this diagnostic to "warning", but make it immune to -Werror. This
|
||||
/// happens when you specify -Wno-error=foo.
|
||||
MAP_WARNING_NO_WERROR = 5,
|
||||
/// Map this diagnostic to "error", but make it immune to -Wfatal-errors.
|
||||
/// This happens for -Wno-fatal-errors=foo.
|
||||
MAP_ERROR_NO_WFATAL = 6
|
||||
};
|
||||
}
|
||||
class DiagnosticErrorTrap;
|
||||
|
||||
/// \brief Annotates a diagnostic with some code that should be
|
||||
/// inserted, removed, or replaced to fix the problem.
|
||||
@ -153,12 +101,17 @@ class FixItHint {
|
||||
/// Diagnostic - This concrete class is used by the front-end to report
|
||||
/// problems and issues. It massages the diagnostics (e.g. handling things like
|
||||
/// "report warnings as errors" and passes them off to the DiagnosticClient for
|
||||
/// reporting to the user.
|
||||
/// reporting to the user. Diagnostic is tied to one translation unit and
|
||||
/// one SourceManager.
|
||||
class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
public:
|
||||
/// Level - The level of the diagnostic, after it has been through mapping.
|
||||
enum Level {
|
||||
Ignored, Note, Warning, Error, Fatal
|
||||
Ignored = DiagnosticIDs::Ignored,
|
||||
Note = DiagnosticIDs::Note,
|
||||
Warning = DiagnosticIDs::Warning,
|
||||
Error = DiagnosticIDs::Error,
|
||||
Fatal = DiagnosticIDs::Fatal
|
||||
};
|
||||
|
||||
/// ExtensionHandling - How do we handle otherwise-unmapped extension? This
|
||||
@ -203,33 +156,94 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack,
|
||||
// 0 -> no limit.
|
||||
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
|
||||
llvm::OwningPtr<DiagnosticClient> Client;
|
||||
|
||||
/// DiagMappings - Mapping information for diagnostics. Mapping info is
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags;
|
||||
DiagnosticClient *Client;
|
||||
bool OwnsDiagClient;
|
||||
SourceManager *SourceMgr;
|
||||
|
||||
/// \brief Mapping information for diagnostics. Mapping info is
|
||||
/// packed into four bits per diagnostic. The low three bits are the mapping
|
||||
/// (an instance of diag::Mapping), or zero if unset. The high bit is set
|
||||
/// when the mapping was established as a user mapping. If the high bit is
|
||||
/// clear, then the low bits are set to the default value, and should be
|
||||
/// mapped with -pedantic, -Werror, etc.
|
||||
class DiagMappings {
|
||||
unsigned char Values[diag::DIAG_UPPER_LIMIT/2];
|
||||
///
|
||||
/// A new DiagState is created and kept around when diagnostic pragmas modify
|
||||
/// the state so that we know what is the diagnostic state at any given
|
||||
/// source location.
|
||||
class DiagState {
|
||||
llvm::DenseMap<unsigned, unsigned> DiagMap;
|
||||
|
||||
public:
|
||||
DiagMappings() {
|
||||
memset(Values, 0, diag::DIAG_UPPER_LIMIT/2);
|
||||
}
|
||||
typedef llvm::DenseMap<unsigned, unsigned>::const_iterator iterator;
|
||||
|
||||
void setMapping(diag::kind Diag, unsigned Map) {
|
||||
size_t Shift = (Diag & 1)*4;
|
||||
Values[Diag/2] = (Values[Diag/2] & ~(15 << Shift)) | (Map << Shift);
|
||||
}
|
||||
void setMapping(diag::kind Diag, unsigned Map) { DiagMap[Diag] = Map; }
|
||||
|
||||
diag::Mapping getMapping(diag::kind Diag) const {
|
||||
return (diag::Mapping)((Values[Diag/2] >> (Diag & 1)*4) & 15);
|
||||
iterator I = DiagMap.find(Diag);
|
||||
if (I != DiagMap.end())
|
||||
return (diag::Mapping)I->second;
|
||||
return diag::Mapping();
|
||||
}
|
||||
|
||||
iterator begin() const { return DiagMap.begin(); }
|
||||
iterator end() const { return DiagMap.end(); }
|
||||
};
|
||||
|
||||
/// \brief Keeps and automatically disposes all DiagStates that we create.
|
||||
std::list<DiagState> DiagStates;
|
||||
|
||||
/// \brief Represents a point in source where the diagnostic state was
|
||||
/// modified because of a pragma. 'Loc' can be null if the point represents
|
||||
/// the diagnostic state modifications done through the command-line.
|
||||
struct DiagStatePoint {
|
||||
DiagState *State;
|
||||
FullSourceLoc Loc;
|
||||
DiagStatePoint(DiagState *State, FullSourceLoc Loc)
|
||||
: State(State), Loc(Loc) { }
|
||||
|
||||
bool operator<(const DiagStatePoint &RHS) const {
|
||||
// If Loc is invalid it means it came from <command-line>, in which case
|
||||
// we regard it as coming before any valid source location.
|
||||
if (RHS.Loc.isInvalid())
|
||||
return false;
|
||||
if (Loc.isInvalid())
|
||||
return true;
|
||||
return Loc.isBeforeInTranslationUnitThan(RHS.Loc);
|
||||
}
|
||||
};
|
||||
|
||||
mutable std::vector<DiagMappings> DiagMappingsStack;
|
||||
/// \brief A vector of all DiagStatePoints representing changes in diagnostic
|
||||
/// state due to diagnostic pragmas. The vector is always sorted according to
|
||||
/// the SourceLocation of the DiagStatePoint.
|
||||
typedef std::vector<DiagStatePoint> DiagStatePointsTy;
|
||||
mutable DiagStatePointsTy DiagStatePoints;
|
||||
|
||||
/// \brief Keeps the DiagState that was active during each diagnostic 'push'
|
||||
/// so we can get back at it when we 'pop'.
|
||||
std::vector<DiagState *> DiagStateOnPushStack;
|
||||
|
||||
DiagState *GetCurDiagState() const {
|
||||
assert(!DiagStatePoints.empty());
|
||||
return DiagStatePoints.back().State;
|
||||
}
|
||||
|
||||
void PushDiagStatePoint(DiagState *State, SourceLocation L) {
|
||||
FullSourceLoc Loc(L, *SourceMgr);
|
||||
// Make sure that DiagStatePoints is always sorted according to Loc.
|
||||
assert((Loc.isValid() || DiagStatePoints.empty()) &&
|
||||
"Adding invalid loc point after another point");
|
||||
assert((Loc.isInvalid() || DiagStatePoints.empty() ||
|
||||
DiagStatePoints.back().Loc.isInvalid() ||
|
||||
DiagStatePoints.back().Loc.isBeforeInTranslationUnitThan(Loc)) &&
|
||||
"Previous point loc comes after or is the same as new one");
|
||||
DiagStatePoints.push_back(DiagStatePoint(State,
|
||||
FullSourceLoc(Loc, *SourceMgr)));
|
||||
}
|
||||
|
||||
/// \brief Finds the DiagStatePoint that contains the diagnostic state of
|
||||
/// the given source location.
|
||||
DiagStatePointsTy::iterator GetDiagStatePointForLoc(SourceLocation Loc) const;
|
||||
|
||||
/// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or
|
||||
/// fatal error is emitted, and is sticky.
|
||||
@ -239,14 +253,11 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// LastDiagLevel - This is the level of the last diagnostic emitted. This is
|
||||
/// used to emit continuation diagnostics with the same level as the
|
||||
/// diagnostic that they follow.
|
||||
Diagnostic::Level LastDiagLevel;
|
||||
DiagnosticIDs::Level LastDiagLevel;
|
||||
|
||||
unsigned NumWarnings; // Number of warnings reported
|
||||
unsigned NumErrors; // Number of errors reported
|
||||
unsigned NumErrorsSuppressed; // Number of errors suppressed
|
||||
|
||||
/// CustomDiagInfo - Information for uniquing and looking up custom diags.
|
||||
diag::CustomDiagInfo *CustomDiagInfo;
|
||||
|
||||
/// ArgToStringFn - A function pointer that converts an opaque diagnostic
|
||||
/// argument to a strings. This takes the modifiers and argument that was
|
||||
@ -279,34 +290,52 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
std::string DelayedDiagArg2;
|
||||
|
||||
public:
|
||||
explicit Diagnostic(DiagnosticClient *client = 0);
|
||||
explicit Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
|
||||
DiagnosticClient *client = 0,
|
||||
bool ShouldOwnClient = true);
|
||||
~Diagnostic();
|
||||
|
||||
const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const {
|
||||
return Diags;
|
||||
}
|
||||
|
||||
DiagnosticClient *getClient() { return Client; }
|
||||
const DiagnosticClient *getClient() const { return Client; }
|
||||
|
||||
/// \brief Return the current diagnostic client along with ownership of that
|
||||
/// client.
|
||||
DiagnosticClient *takeClient() {
|
||||
OwnsDiagClient = false;
|
||||
return Client;
|
||||
}
|
||||
|
||||
bool hasSourceManager() const { return SourceMgr != 0; }
|
||||
SourceManager &getSourceManager() const {
|
||||
assert(SourceMgr && "SourceManager not set!");
|
||||
return *SourceMgr;
|
||||
}
|
||||
void setSourceManager(SourceManager *SrcMgr) { SourceMgr = SrcMgr; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic characterization methods, used by a client to customize how
|
||||
// diagnostics are emitted.
|
||||
//
|
||||
|
||||
DiagnosticClient *getClient() { return Client.get(); }
|
||||
const DiagnosticClient *getClient() const { return Client.get(); }
|
||||
|
||||
/// \brief Return the current diagnostic client along with ownership of that
|
||||
/// client.
|
||||
DiagnosticClient *takeClient() { return Client.take(); }
|
||||
|
||||
/// pushMappings - Copies the current DiagMappings and pushes the new copy
|
||||
/// onto the top of the stack.
|
||||
void pushMappings();
|
||||
void pushMappings(SourceLocation Loc);
|
||||
|
||||
/// popMappings - Pops the current DiagMappings off the top of the stack
|
||||
/// causing the new top of the stack to be the active mappings. Returns
|
||||
/// true if the pop happens, false if there is only one DiagMapping on the
|
||||
/// stack.
|
||||
bool popMappings();
|
||||
bool popMappings(SourceLocation Loc);
|
||||
|
||||
/// \brief Set the diagnostic client associated with this diagnostic object.
|
||||
///
|
||||
/// The diagnostic object takes ownership of \c client.
|
||||
void setClient(DiagnosticClient* client) { Client.reset(client); }
|
||||
/// \param ShouldOwnClient true if the diagnostic object should take
|
||||
/// ownership of \c client.
|
||||
void setClient(DiagnosticClient *client, bool ShouldOwnClient = true);
|
||||
|
||||
/// setErrorLimit - Specify a limit for the number of errors we should
|
||||
/// emit before giving up. Zero disables the limit.
|
||||
@ -362,7 +391,7 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// \brief Pretend that the last diagnostic issued was ignored. This can
|
||||
/// be used by clients who suppress diagnostics themselves.
|
||||
void setLastDiagnosticIgnored() {
|
||||
LastDiagLevel = Ignored;
|
||||
LastDiagLevel = DiagnosticIDs::Ignored;
|
||||
}
|
||||
|
||||
/// setExtensionHandlingBehavior - This controls whether otherwise-unmapped
|
||||
@ -379,28 +408,29 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; }
|
||||
bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; }
|
||||
|
||||
/// setDiagnosticMapping - This allows the client to specify that certain
|
||||
/// \brief This allows the client to specify that certain
|
||||
/// warnings are ignored. Notes can never be mapped, errors can only be
|
||||
/// mapped to fatal, and WARNINGs and EXTENSIONs can be mapped arbitrarily.
|
||||
void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) {
|
||||
assert(Diag < diag::DIAG_UPPER_LIMIT &&
|
||||
"Can only map builtin diagnostics");
|
||||
assert((isBuiltinWarningOrExtension(Diag) ||
|
||||
(Map == diag::MAP_FATAL || Map == diag::MAP_ERROR)) &&
|
||||
"Cannot map errors into warnings!");
|
||||
setDiagnosticMappingInternal(Diag, Map, true);
|
||||
}
|
||||
///
|
||||
/// \param Loc The source location that this change of diagnostic state should
|
||||
/// take affect. It can be null if we are setting the latest state.
|
||||
void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
|
||||
SourceLocation Loc);
|
||||
|
||||
/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
|
||||
/// "unknown-pragmas" to have the specified mapping. This returns true and
|
||||
/// ignores the request if "Group" was unknown, false otherwise.
|
||||
bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map);
|
||||
///
|
||||
/// 'Loc' is the source location that this change of diagnostic state should
|
||||
/// take affect. It can be null if we are setting the state from command-line.
|
||||
bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map,
|
||||
SourceLocation Loc = SourceLocation()) {
|
||||
return Diags->setDiagnosticGroupMapping(Group, Map, Loc, *this);
|
||||
}
|
||||
|
||||
bool hasErrorOccurred() const { return ErrorOccurred; }
|
||||
bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
|
||||
|
||||
unsigned getNumErrors() const { return NumErrors; }
|
||||
unsigned getNumErrorsSuppressed() const { return NumErrorsSuppressed; }
|
||||
unsigned getNumWarnings() const { return NumWarnings; }
|
||||
|
||||
void setNumWarnings(unsigned NumWarnings) {
|
||||
@ -410,8 +440,9 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
|
||||
/// and level. If this is the first request for this diagnosic, it is
|
||||
/// registered and created, otherwise the existing ID is returned.
|
||||
unsigned getCustomDiagID(Level L, llvm::StringRef Message);
|
||||
|
||||
unsigned getCustomDiagID(Level L, llvm::StringRef Message) {
|
||||
return Diags->getCustomDiagID((DiagnosticIDs::Level)L, Message);
|
||||
}
|
||||
|
||||
/// ConvertArgToString - This method converts a diagnostic argument (as an
|
||||
/// intptr_t) into the string that represents it.
|
||||
@ -437,92 +468,22 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
// Diagnostic classification and reporting interfaces.
|
||||
//
|
||||
|
||||
/// getDescription - Given a diagnostic ID, return a description of the
|
||||
/// issue.
|
||||
const char *getDescription(unsigned DiagID) const;
|
||||
|
||||
/// isNoteWarningOrExtension - Return true if the unmapped diagnostic
|
||||
/// level of the specified diagnostic ID is a Warning or Extension.
|
||||
/// This only works on builtin diagnostics, not custom ones, and is not legal to
|
||||
/// call on NOTEs.
|
||||
static bool isBuiltinWarningOrExtension(unsigned DiagID);
|
||||
|
||||
/// \brief Determine whether the given built-in diagnostic ID is a
|
||||
/// Note.
|
||||
static bool isBuiltinNote(unsigned DiagID);
|
||||
|
||||
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
|
||||
/// ID is for an extension of some sort.
|
||||
///
|
||||
static bool isBuiltinExtensionDiag(unsigned DiagID) {
|
||||
bool ignored;
|
||||
return isBuiltinExtensionDiag(DiagID, ignored);
|
||||
}
|
||||
|
||||
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
|
||||
/// ID is for an extension of some sort. This also returns EnabledByDefault,
|
||||
/// which is set to indicate whether the diagnostic is ignored by default (in
|
||||
/// which case -pedantic enables it) or treated as a warning/error by default.
|
||||
///
|
||||
static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault);
|
||||
|
||||
|
||||
/// getWarningOptionForDiag - Return the lowest-level warning option that
|
||||
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
|
||||
/// the diagnostic, this returns null.
|
||||
static const char *getWarningOptionForDiag(unsigned DiagID);
|
||||
|
||||
/// getWarningOptionForDiag - Return the category number that a specified
|
||||
/// DiagID belongs to, or 0 if no category.
|
||||
static unsigned getCategoryNumberForDiag(unsigned DiagID);
|
||||
|
||||
/// getCategoryNameFromID - Given a category ID, return the name of the
|
||||
/// category.
|
||||
static const char *getCategoryNameFromID(unsigned CategoryID);
|
||||
|
||||
/// \brief Enumeration describing how the the emission of a diagnostic should
|
||||
/// be treated when it occurs during C++ template argument deduction.
|
||||
enum SFINAEResponse {
|
||||
/// \brief The diagnostic should not be reported, but it should cause
|
||||
/// template argument deduction to fail.
|
||||
///
|
||||
/// The vast majority of errors that occur during template argument
|
||||
/// deduction fall into this category.
|
||||
SFINAE_SubstitutionFailure,
|
||||
|
||||
/// \brief The diagnostic should be suppressed entirely.
|
||||
///
|
||||
/// Warnings generally fall into this category.
|
||||
SFINAE_Suppress,
|
||||
|
||||
/// \brief The diagnostic should be reported.
|
||||
///
|
||||
/// The diagnostic should be reported. Various fatal errors (e.g.,
|
||||
/// template instantiation depth exceeded) fall into this category.
|
||||
SFINAE_Report
|
||||
};
|
||||
|
||||
/// \brief Determines whether the given built-in diagnostic ID is
|
||||
/// for an error that is suppressed if it occurs during C++ template
|
||||
/// argument deduction.
|
||||
///
|
||||
/// When an error is suppressed due to SFINAE, the template argument
|
||||
/// deduction fails but no diagnostic is emitted. Certain classes of
|
||||
/// errors, such as those errors that involve C++ access control,
|
||||
/// are not SFINAE errors.
|
||||
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
|
||||
|
||||
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
|
||||
/// \brief Based on the way the client configured the Diagnostic
|
||||
/// object, classify the specified diagnostic ID into a Level, consumable by
|
||||
/// the DiagnosticClient.
|
||||
Level getDiagnosticLevel(unsigned DiagID) const;
|
||||
///
|
||||
/// \param Loc The source location we are interested in finding out the
|
||||
/// diagnostic state. Can be null in order to query the latest state.
|
||||
Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const {
|
||||
return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this);
|
||||
}
|
||||
|
||||
/// Report - Issue the message to the client. @c DiagID is a member of the
|
||||
/// @c diag::kind enum. This actually returns aninstance of DiagnosticBuilder
|
||||
/// which emits the diagnostics (through @c ProcessDiag) when it is destroyed.
|
||||
/// @c Pos represents the source location associated with the diagnostic,
|
||||
/// which can be an invalid location if no position information is available.
|
||||
inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID);
|
||||
inline DiagnosticBuilder Report(SourceLocation Pos, unsigned DiagID);
|
||||
inline DiagnosticBuilder Report(unsigned DiagID);
|
||||
|
||||
/// \brief Determine whethere there is already a diagnostic in flight.
|
||||
@ -563,32 +524,34 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// getDiagnosticMappingInfo - Return the mapping info currently set for the
|
||||
/// specified builtin diagnostic. This returns the high bit encoding, or zero
|
||||
/// if the field is completely uninitialized.
|
||||
diag::Mapping getDiagnosticMappingInfo(diag::kind Diag) const {
|
||||
return DiagMappingsStack.back().getMapping(Diag);
|
||||
diag::Mapping getDiagnosticMappingInfo(diag::kind Diag,
|
||||
DiagState *State) const {
|
||||
return State->getMapping(Diag);
|
||||
}
|
||||
|
||||
void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map,
|
||||
bool isUser) const {
|
||||
DiagState *State,
|
||||
bool isUser, bool isPragma) const {
|
||||
if (isUser) Map |= 8; // Set the high bit for user mappings.
|
||||
DiagMappingsStack.back().setMapping((diag::kind)DiagId, Map);
|
||||
if (isPragma) Map |= 0x10; // Set the bit for diagnostic pragma mappings.
|
||||
State->setMapping((diag::kind)DiagId, Map);
|
||||
}
|
||||
|
||||
/// getDiagnosticLevel - This is an internal implementation helper used when
|
||||
/// DiagClass is already known.
|
||||
Level getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const;
|
||||
|
||||
// This is private state used by DiagnosticBuilder. We put it here instead of
|
||||
// in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight
|
||||
// object. This implementation choice means that we can only have one
|
||||
// diagnostic "in flight" at a time, but this seems to be a reasonable
|
||||
// tradeoff to keep these objects small. Assertions verify that only one
|
||||
// diagnostic is in flight at a time.
|
||||
friend class DiagnosticIDs;
|
||||
friend class DiagnosticBuilder;
|
||||
friend class DiagnosticInfo;
|
||||
|
||||
friend class PartialDiagnostic;
|
||||
friend class DiagnosticErrorTrap;
|
||||
|
||||
/// CurDiagLoc - This is the location of the current diagnostic that is in
|
||||
/// flight.
|
||||
FullSourceLoc CurDiagLoc;
|
||||
SourceLocation CurDiagLoc;
|
||||
|
||||
/// CurDiagID - This is the ID of the current diagnostic that is in flight.
|
||||
/// This is set to ~0U when there is no diagnostic in flight.
|
||||
@ -640,7 +603,33 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
///
|
||||
/// \returns true if the diagnostic was emitted, false if it was
|
||||
/// suppressed.
|
||||
bool ProcessDiag();
|
||||
bool ProcessDiag() {
|
||||
return Diags->ProcessDiag(*this);
|
||||
}
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTWriter;
|
||||
};
|
||||
|
||||
/// \brief RAII class that determines when any errors have occurred
|
||||
/// between the time the instance was created and the time it was
|
||||
/// queried.
|
||||
class DiagnosticErrorTrap {
|
||||
Diagnostic &Diag;
|
||||
unsigned PrevErrors;
|
||||
|
||||
public:
|
||||
explicit DiagnosticErrorTrap(Diagnostic &Diag)
|
||||
: Diag(Diag), PrevErrors(Diag.NumErrors) {}
|
||||
|
||||
/// \brief Determine whether any errors have occurred since this
|
||||
/// object instance was created.
|
||||
bool hasErrorOccurred() const {
|
||||
return Diag.NumErrors > PrevErrors;
|
||||
}
|
||||
|
||||
// Set to initial state of "no errors occurred".
|
||||
void reset() { PrevErrors = Diag.NumErrors; }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -667,6 +656,11 @@ class DiagnosticBuilder {
|
||||
explicit DiagnosticBuilder(Diagnostic *diagObj)
|
||||
: DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {}
|
||||
|
||||
friend class PartialDiagnostic;
|
||||
|
||||
protected:
|
||||
void FlushCounts();
|
||||
|
||||
public:
|
||||
/// Copy constructor. When copied, this "takes" the diagnostic info from the
|
||||
/// input and neuters it.
|
||||
@ -703,6 +697,17 @@ class DiagnosticBuilder {
|
||||
/// isActive - Determine whether this diagnostic is still active.
|
||||
bool isActive() const { return DiagObj != 0; }
|
||||
|
||||
/// \brief Retrieve the active diagnostic ID.
|
||||
///
|
||||
/// \pre \c isActive()
|
||||
unsigned getDiagID() const {
|
||||
assert(isActive() && "Diagnostic is inactive");
|
||||
return DiagObj->CurDiagID;
|
||||
}
|
||||
|
||||
/// \brief Clear out the current diagnostic.
|
||||
void Clear() { DiagObj = 0; }
|
||||
|
||||
/// Operator bool: conversion of DiagnosticBuilder to bool always returns
|
||||
/// true. This allows is to be used in boolean error contexts like:
|
||||
/// return Diag(...);
|
||||
@ -816,14 +821,15 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
/// Report - Issue the message to the client. DiagID is a member of the
|
||||
/// diag::kind enum. This actually returns a new instance of DiagnosticBuilder
|
||||
/// which emits the diagnostics (through ProcessDiag) when it is destroyed.
|
||||
inline DiagnosticBuilder Diagnostic::Report(FullSourceLoc Loc, unsigned DiagID){
|
||||
inline DiagnosticBuilder Diagnostic::Report(SourceLocation Loc,
|
||||
unsigned DiagID){
|
||||
assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
|
||||
CurDiagLoc = Loc;
|
||||
CurDiagID = DiagID;
|
||||
return DiagnosticBuilder(this);
|
||||
}
|
||||
inline DiagnosticBuilder Diagnostic::Report(unsigned DiagID) {
|
||||
return Report(FullSourceLoc(), DiagID);
|
||||
return Report(SourceLocation(), DiagID);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -840,7 +846,9 @@ class DiagnosticInfo {
|
||||
|
||||
const Diagnostic *getDiags() const { return DiagObj; }
|
||||
unsigned getID() const { return DiagObj->CurDiagID; }
|
||||
const FullSourceLoc &getLocation() const { return DiagObj->CurDiagLoc; }
|
||||
const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; }
|
||||
bool hasSourceManager() const { return DiagObj->hasSourceManager(); }
|
||||
SourceManager &getSourceManager() const { return DiagObj->getSourceManager();}
|
||||
|
||||
unsigned getNumArgs() const { return DiagObj->NumDiagArgs; }
|
||||
|
||||
@ -930,10 +938,11 @@ class DiagnosticInfo {
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Represents a diagnostic in a form that can be serialized and
|
||||
* deserialized.
|
||||
* \brief Represents a diagnostic in a form that can be retained until its
|
||||
* corresponding source manager is destroyed.
|
||||
*/
|
||||
class StoredDiagnostic {
|
||||
unsigned ID;
|
||||
Diagnostic::Level Level;
|
||||
FullSourceLoc Loc;
|
||||
std::string Message;
|
||||
@ -943,12 +952,14 @@ class StoredDiagnostic {
|
||||
public:
|
||||
StoredDiagnostic();
|
||||
StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info);
|
||||
StoredDiagnostic(Diagnostic::Level Level, llvm::StringRef Message);
|
||||
StoredDiagnostic(Diagnostic::Level Level, unsigned ID,
|
||||
llvm::StringRef Message);
|
||||
~StoredDiagnostic();
|
||||
|
||||
/// \brief Evaluates true when this object stores a diagnostic.
|
||||
operator bool() const { return Message.size() > 0; }
|
||||
|
||||
unsigned getID() const { return ID; }
|
||||
Diagnostic::Level getLevel() const { return Level; }
|
||||
const FullSourceLoc &getLocation() const { return Loc; }
|
||||
llvm::StringRef getMessage() const { return Message; }
|
||||
@ -964,25 +975,21 @@ class StoredDiagnostic {
|
||||
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(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
|
||||
/// the front-end, which formats and prints fully processed diagnostics.
|
||||
class DiagnosticClient {
|
||||
protected:
|
||||
unsigned NumWarnings; // Number of warnings reported
|
||||
unsigned NumErrors; // Number of errors reported
|
||||
|
||||
public:
|
||||
DiagnosticClient() : NumWarnings(0), NumErrors(0) { }
|
||||
|
||||
unsigned getNumErrors() const { return NumErrors; }
|
||||
unsigned getNumWarnings() const { return NumWarnings; }
|
||||
|
||||
virtual ~DiagnosticClient();
|
||||
|
||||
/// BeginSourceFile - Callback to inform the diagnostic client that processing
|
||||
@ -1012,8 +1019,11 @@ class DiagnosticClient {
|
||||
|
||||
/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
|
||||
/// capturing it to a log as needed.
|
||||
///
|
||||
/// Default implementation just keeps track of the total number of warnings
|
||||
/// and errors.
|
||||
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
||||
const DiagnosticInfo &Info) = 0;
|
||||
const DiagnosticInfo &Info);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -56,6 +56,7 @@ class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
|
||||
string Text = text;
|
||||
DiagClass Class = DC;
|
||||
bit SFINAE = 1;
|
||||
bit AccessControl = 0;
|
||||
DiagMapping DefaultMapping = defaultmapping;
|
||||
DiagGroup Group;
|
||||
string CategoryName = "";
|
||||
@ -74,6 +75,7 @@ class DefaultError { DiagMapping DefaultMapping = MAP_ERROR; }
|
||||
class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; }
|
||||
|
||||
class NoSFINAE { bit SFINAE = 0; }
|
||||
class AccessControl { bit AccessControl = 1; }
|
||||
|
||||
// Definitions for Diagnostics.
|
||||
include "DiagnosticASTKinds.td"
|
||||
|
@ -56,6 +56,8 @@ 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">;
|
||||
|
||||
// Importing Objective-C ASTs
|
||||
def err_odr_ivar_type_inconsistent : Error<
|
||||
"instance variable %0 declared with incompatible types in different "
|
||||
"translation units (%1 vs. %2)">;
|
||||
@ -80,5 +82,32 @@ def note_odr_objc_method_here : Note<
|
||||
def err_odr_objc_property_type_inconsistent : Error<
|
||||
"property %0 declared with incompatible types in different "
|
||||
"translation units (%1 vs. %2)">;
|
||||
def err_odr_objc_property_impl_kind_inconsistent : Error<
|
||||
"property %0 is implemented with %select{@synthesize|@dynamic}1 in one "
|
||||
"translation but %select{@dynamic|@synthesize}1 in another translation unit">;
|
||||
def note_odr_objc_property_impl_kind : Note<
|
||||
"property %0 is implemented with %select{@synthesize|@dynamic}1 here">;
|
||||
def err_odr_objc_synthesize_ivar_inconsistent : Error<
|
||||
"property %0 is synthesized to different ivars in different translation "
|
||||
"units (%1 vs. %2)">;
|
||||
def note_odr_objc_synthesize_ivar_here : Note<
|
||||
"property is synthesized to ivar %0 here">;
|
||||
|
||||
// Importing C++ ASTs
|
||||
def err_odr_different_num_template_parameters : Error<
|
||||
"template parameter lists have a different number of parameters (%0 vs %1)">;
|
||||
def note_odr_template_parameter_list : Note<
|
||||
"template parameter list also declared here">;
|
||||
def err_odr_different_template_parameter_kind : Error<
|
||||
"template parameter has different kinds in different translation units">;
|
||||
def note_odr_template_parameter_here : Note<
|
||||
"template parameter declared here">;
|
||||
def err_odr_parameter_pack_non_pack : Error<
|
||||
"parameter kind mismatch; parameter is %select{not a|a}0 parameter pack">;
|
||||
def note_odr_parameter_pack_non_pack : Note<
|
||||
"%select{parameter|parameter pack}0 declared here">;
|
||||
def err_odr_non_type_parameter_type_inconsistent : Error<
|
||||
"non-type template parameter declared with incompatible types in different "
|
||||
"translation units (%0 vs. %1)">;
|
||||
def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">;
|
||||
}
|
||||
|
@ -44,9 +44,12 @@ def err_expected_colon_after_setter_name : Error<
|
||||
def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
|
||||
InGroup<MissingDeclarations>;
|
||||
def err_param_redefinition : Error<"redefinition of parameter %0">;
|
||||
def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">;
|
||||
def err_invalid_storage_class_in_func_decl : Error<
|
||||
"invalid storage class specifier in function declarator">;
|
||||
def err_expected_namespace_name : Error<"expected namespace name">;
|
||||
def ext_variadic_templates : ExtWarn<
|
||||
"variadic templates are a C++0x extension">, InGroup<CXX0x>;
|
||||
|
||||
// Sema && Lex
|
||||
def ext_longlong : Extension<
|
||||
|
@ -11,11 +11,15 @@ let Component = "Driver" in {
|
||||
|
||||
def err_drv_no_such_file : Error<"no such file or directory: '%0'">;
|
||||
def err_drv_unsupported_opt : Error<"unsupported option '%0'">;
|
||||
def err_drv_unsupported_option_argument : Error<
|
||||
"unsupported argument '%1' to option '%0'">;
|
||||
def err_drv_unknown_stdin_type : Error<
|
||||
"-E or -x required when input is from standard input">;
|
||||
def err_drv_unknown_language : Error<"language not recognized: '%0'">;
|
||||
def err_drv_invalid_arch_name : Error<
|
||||
"invalid arch name '%0'">;
|
||||
def err_drv_invalid_stdlib_name : Error<
|
||||
"invalid library name in argument '%0'">;
|
||||
def err_drv_invalid_opt_with_multiple_archs : Error<
|
||||
"option '%0' cannot be used with multiple -arch options">;
|
||||
def err_drv_invalid_output_with_multiple_archs : Error<
|
||||
@ -49,6 +53,8 @@ def err_drv_no_ast_support : Error<
|
||||
"'%0': unable to use AST files with this tool">;
|
||||
def err_drv_clang_unsupported : Error<
|
||||
"the clang compiler does not support '%0'">;
|
||||
def err_drv_clang_unsupported_per_platform : Error<
|
||||
"the clang compiler does not support '%0' on this platform">;
|
||||
def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error<
|
||||
"the clang compiler does not support '%0' for C++ on Darwin/i386">;
|
||||
def err_drv_command_failed : Error<
|
||||
@ -71,6 +77,10 @@ def err_drv_cc_print_options_failure : Error<
|
||||
def err_drv_preamble_format : Error<
|
||||
"incorrect format for -preamble-bytes=N,END">;
|
||||
|
||||
def warn_c_kext : Warning<
|
||||
"ignoring -fapple-kext which is valid for c++ and objective-c++ only">;
|
||||
def warn_drv_unsupported_option_argument : Warning<
|
||||
"ignoring unsupported argument '%1' to option '%0'">;
|
||||
def warn_drv_input_file_unused : Warning<
|
||||
"%0: '%1' input unused when '%2' is present">;
|
||||
def warn_drv_preprocessed_input_file_unused : Warning<
|
||||
@ -91,8 +101,6 @@ def warn_drv_assuming_mfloat_abi_is : Warning<
|
||||
"unknown platform, assuming -mfloat-abi=%0">;
|
||||
def warn_ignoring_ftabstop_value : Warning<
|
||||
"ignoring invalid -ftabstop value '%0', using default value %1">;
|
||||
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">;
|
||||
def warn_drv_treating_input_as_cxx : Warning<
|
||||
@ -100,5 +108,7 @@ def warn_drv_treating_input_as_cxx : Warning<
|
||||
InGroup<Deprecated>;
|
||||
def warn_drv_objc_gc_unsupported : Warning<
|
||||
"Objective-C garbage collection is not supported on this platform, ignoring '%0'">;
|
||||
def warn_drv_pch_not_first_include : Warning<
|
||||
"precompiled header '%0' was ignored because '%1' is not first '-include'">;
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ def err_fe_invalid_ast_action : Error<"invalid action for AST input">,
|
||||
DefaultFatal;
|
||||
// Error generated by the backend.
|
||||
def err_fe_inline_asm : Error<"%0">, CatInlineAsm;
|
||||
def note_fe_inline_asm_here : Note<"instantated into assembly here">;
|
||||
def note_fe_inline_asm_here : Note<"instantiated into assembly here">;
|
||||
|
||||
|
||||
|
||||
@ -69,12 +69,16 @@ def err_fe_pch_file_modified : Error<
|
||||
DefaultFatal;
|
||||
def err_fe_unable_to_open_output : Error<
|
||||
"unable to open output file '%0': '%1'">;
|
||||
def err_fe_unable_to_rename_temp : Error<
|
||||
"unable to rename temporary '%0' to output file '%1': '%2'">;
|
||||
def err_fe_unable_to_open_logfile : Error<
|
||||
"unable to open logfile file '%0': '%1'">;
|
||||
def err_fe_pth_file_has_no_source_header : Error<
|
||||
"PTH file '%0' does not designate an original source header file for -include-pth">;
|
||||
def warn_fe_macro_contains_embedded_newline : Warning<
|
||||
"macro '%0' contains embedded newline, text after the newline is ignored.">;
|
||||
def warn_fe_cc_print_header_failure : Warning<
|
||||
"unable to open CC_PRINT_HEADERS file: %0 (using stderr)">;
|
||||
|
||||
def err_verify_missing_start : Error<
|
||||
"cannot find start ('{{') of expected %0">;
|
||||
@ -83,7 +87,8 @@ def err_verify_missing_end : Error<
|
||||
def err_verify_invalid_content : Error<
|
||||
"invalid expected %0: %1">;
|
||||
def err_verify_inconsistent_diags : Error<
|
||||
"'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: %2">;
|
||||
"'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: "
|
||||
"%2">;
|
||||
|
||||
def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
|
||||
def note_fixit_in_macro : Note<
|
||||
@ -127,6 +132,12 @@ def warn_pch_nonfragile_abi2 : Error<
|
||||
"PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 "
|
||||
"Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 "
|
||||
"Objective-C ABI is selected">;
|
||||
def warn_pch_apple_kext : Error<
|
||||
"PCH file was compiled %select{with|without}0 support for Apple's kernel "
|
||||
"extensions ABI but it is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_objc_auto_properties : Error<
|
||||
"PCH file was compiled %select{with|without}0 support for auto-synthesized "
|
||||
"@properties but it is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_no_constant_cfstrings : Error<
|
||||
"Objctive-C NSstring generation support was %select{disabled|enabled}0 "
|
||||
"in PCH file but currently %select{disabled|enabled}1">;
|
||||
@ -142,6 +153,9 @@ def warn_pch_gnu_keywords : Error<
|
||||
def warn_pch_microsoft_extensions : Error<
|
||||
"Microsoft extensions were %select{disabled|enabled}0 in PCH file but are "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_ms_bitfields : Error<
|
||||
"Microsoft-compatible structure layout was %select{disabled|enabled}0 in "
|
||||
"PCH file but is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_heinous_extensions : Error<
|
||||
"heinous extensions were %select{disabled|enabled}0 in PCH file but are "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
@ -154,6 +168,9 @@ def warn_pch_altivec : Error<
|
||||
def warn_pch_opencl : Error<
|
||||
"OpenCL language extensions were %select{disabled|enabled}0 in PCH file "
|
||||
"but are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_cuda : Error<
|
||||
"CUDA language extensions were %select{disabled|enabled}0 in PCH file "
|
||||
"but are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_elide_constructors : Error<
|
||||
"Elidable copy constructors were %select{disabled|enabled}0 in PCH file "
|
||||
"but are currently %select{disabled|enabled}1">;
|
||||
@ -163,6 +180,9 @@ def warn_pch_exceptions : Error<
|
||||
def warn_pch_sjlj_exceptions : Error<
|
||||
"sjlj-exceptions were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_objc_exceptions : Error<
|
||||
"Objective-C exceptions were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_objc_runtime : Error<
|
||||
"PCH file was compiled with the %select{NeXT|GNU}0 runtime but the "
|
||||
"%select{NeXT|GNU}1 runtime is selected">;
|
||||
@ -241,6 +261,9 @@ def warn_pch_char_signed : Error<
|
||||
def warn_pch_short_wchar : Error<
|
||||
"-fshort-wchar was %select{disabled|enabled}0 in the PCH file but "
|
||||
"is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_short_enums : Error<
|
||||
"-fshort-enums was %select{disabled|enabled}0 in the PCH file but "
|
||||
"is currently %select{disabled|enabled}1">;
|
||||
|
||||
def err_not_a_pch_file : Error<
|
||||
"'%0' does not appear to be a precompiled header file">, DefaultFatal;
|
||||
@ -250,4 +273,7 @@ def warn_unknown_warning_option : Warning<
|
||||
def warn_unknown_warning_specifier : Warning<
|
||||
"unknown %0 warning specifier: '%1'">,
|
||||
InGroup<DiagGroup<"unknown-warning-option"> >;
|
||||
|
||||
def warn_unkwown_analyzer_checker : Warning<
|
||||
"no analyzer checkers are associated with '%0'">;
|
||||
}
|
||||
|
@ -35,9 +35,12 @@ def : DiagGroup<"declaration-after-statement">;
|
||||
def GNUDesignator : DiagGroup<"gnu-designator">;
|
||||
|
||||
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
|
||||
def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings">;
|
||||
def Deprecated : DiagGroup<"deprecated", [ DeprecatedDeclarations] >,
|
||||
DiagCategory<"Deprecations">;
|
||||
|
||||
def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
|
||||
|
||||
def : DiagGroup<"disabled-optimization">;
|
||||
def : DiagGroup<"discard-qual">;
|
||||
def : DiagGroup<"div-by-zero">;
|
||||
@ -54,6 +57,7 @@ def : DiagGroup<"effc++">;
|
||||
def FourByteMultiChar : DiagGroup<"four-char-constants">;
|
||||
def GlobalConstructors : DiagGroup<"global-constructors">;
|
||||
def : DiagGroup<"idiomatic-parentheses">;
|
||||
def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
|
||||
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
|
||||
def : DiagGroup<"import">;
|
||||
def : DiagGroup<"init-self">;
|
||||
@ -74,17 +78,19 @@ def : DiagGroup<"newline-eof">;
|
||||
def LongLong : DiagGroup<"long-long">;
|
||||
def MismatchedTags : DiagGroup<"mismatched-tags">;
|
||||
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
|
||||
def NullDereference : DiagGroup<"null-dereference">;
|
||||
def InitializerOverrides : DiagGroup<"initializer-overrides">;
|
||||
def NonNull : DiagGroup<"nonnull">;
|
||||
def : DiagGroup<"nonportable-cfstrings">;
|
||||
def : DiagGroup<"non-virtual-dtor">;
|
||||
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
|
||||
def : DiagGroup<"old-style-cast">;
|
||||
def : DiagGroup<"old-style-definition">;
|
||||
def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">;
|
||||
def : DiagGroup<"overflow">;
|
||||
def OverlengthStrings : DiagGroup<"overlength-strings">;
|
||||
def : DiagGroup<"overloaded-virtual">;
|
||||
def : DiagGroup<"packed">;
|
||||
def OverloadedVirtual : DiagGroup<"overloaded-virtual">;
|
||||
def Packed : DiagGroup<"packed">;
|
||||
def Padded : DiagGroup<"padded">;
|
||||
def PointerArith : DiagGroup<"pointer-arith">;
|
||||
def PoundWarning : DiagGroup<"#warnings">,
|
||||
DiagCategory<"#warning Directive">;
|
||||
@ -92,6 +98,7 @@ def : DiagGroup<"pointer-to-int-cast">;
|
||||
def : DiagGroup<"redundant-decls">;
|
||||
def ReturnType : DiagGroup<"return-type">;
|
||||
def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy">;
|
||||
def SelfAssignment : DiagGroup<"self-assign">;
|
||||
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
|
||||
def : DiagGroup<"sequence-point">;
|
||||
def Shadow : DiagGroup<"shadow">;
|
||||
@ -101,6 +108,7 @@ def SignCompare : DiagGroup<"sign-compare">;
|
||||
def : DiagGroup<"stack-protector">;
|
||||
def : DiagGroup<"switch-default">;
|
||||
def : DiagGroup<"synth">;
|
||||
def TautologicalCompare : DiagGroup<"tautological-compare">;
|
||||
|
||||
// Preprocessor warnings.
|
||||
def : DiagGroup<"builtin-macro-redefined">;
|
||||
@ -140,9 +148,14 @@ def UnusedLabel : DiagGroup<"unused-label">;
|
||||
def UnusedParameter : DiagGroup<"unused-parameter">;
|
||||
def UnusedValue : DiagGroup<"unused-value">;
|
||||
def UnusedVariable : DiagGroup<"unused-variable">;
|
||||
def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
|
||||
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
|
||||
def Reorder : DiagGroup<"reorder">;
|
||||
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
|
||||
def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">;
|
||||
def CustomAtomic : DiagGroup<"custom-atomic-properties">;
|
||||
def AtomicProperties : DiagGroup<"atomic-properties",
|
||||
[ImplicitAtomic, CustomAtomic]>;
|
||||
def Selector : DiagGroup<"selector">;
|
||||
def NonfragileAbi2 : DiagGroup<"nonfragile-abi2">;
|
||||
def Protocol : DiagGroup<"protocol">;
|
||||
@ -154,17 +167,27 @@ def VLA : DiagGroup<"vla">;
|
||||
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
|
||||
def : DiagGroup<"write-strings">;
|
||||
def CharSubscript : DiagGroup<"char-subscripts">;
|
||||
def LargeByValueCopy : DiagGroup<"large-by-value-copy">;
|
||||
|
||||
// Aggregation warning settings.
|
||||
|
||||
// -Widiomatic-parentheses contains warnings about 'idiomatic'
|
||||
// missing parentheses; it is off by default.
|
||||
def Parentheses : DiagGroup<"parentheses", [DiagGroup<"idiomatic-parentheses">]>;
|
||||
def Parentheses : DiagGroup<"parentheses",
|
||||
[LogicalOpParentheses,
|
||||
DiagGroup<"idiomatic-parentheses">]>;
|
||||
|
||||
// -Wconversion has its own warnings, but we split this one out for
|
||||
// legacy reasons.
|
||||
// -Wconversion has its own warnings, but we split a few out for
|
||||
// legacy reasons:
|
||||
// - some people want just 64-to-32 warnings
|
||||
// - conversion warnings with constant sources are on by default
|
||||
// - conversion warnings for literals are on by default
|
||||
// - bool-to-pointer conversion warnings are on by default
|
||||
def Conversion : DiagGroup<"conversion",
|
||||
[DiagGroup<"shorten-64-to-32">, BoolConversions]>,
|
||||
[DiagGroup<"shorten-64-to-32">,
|
||||
DiagGroup<"constant-conversion">,
|
||||
DiagGroup<"literal-conversion">,
|
||||
BoolConversions]>,
|
||||
DiagCategory<"Value Conversion Issue">;
|
||||
|
||||
def Unused : DiagGroup<"unused",
|
||||
@ -202,13 +225,15 @@ def Most : DiagGroup<"most", [
|
||||
MultiChar,
|
||||
Reorder,
|
||||
ReturnType,
|
||||
SelfAssignment,
|
||||
Switch,
|
||||
Trigraphs,
|
||||
Uninitialized,
|
||||
UnknownPragmas,
|
||||
Unused,
|
||||
VectorConversions,
|
||||
VolatileRegisterVar
|
||||
VolatileRegisterVar,
|
||||
OverloadedVirtual
|
||||
]>;
|
||||
|
||||
// -Wall is -Wmost -Wparentheses
|
||||
@ -224,5 +249,12 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
|
||||
def NonGCC : DiagGroup<"non-gcc",
|
||||
[SignCompare, Conversion, LiteralRange]>;
|
||||
|
||||
// A warning group for warnings about using C++0x features as extensions in
|
||||
// earlier C++ versions.
|
||||
def CXX0x : DiagGroup<"c++0x-extensions">;
|
||||
|
||||
// A warning group for warnings about GCC extensions.
|
||||
def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>;
|
||||
|
||||
// A warning group for warnings about Microsoft extensions.
|
||||
def Microsoft : DiagGroup<"microsoft">;
|
||||
|
212
include/clang/Basic/DiagnosticIDs.h
Normal file
212
include/clang/Basic/DiagnosticIDs.h
Normal file
@ -0,0 +1,212 @@
|
||||
//===--- DiagnosticIDs.h - Diagnostic IDs Handling --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the Diagnostic IDs-related interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_DIAGNOSTICIDS_H
|
||||
#define LLVM_CLANG_DIAGNOSTICIDS_H
|
||||
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clang {
|
||||
class Diagnostic;
|
||||
class SourceLocation;
|
||||
|
||||
// Import the diagnostic enums themselves.
|
||||
namespace diag {
|
||||
// Start position for diagnostics.
|
||||
enum {
|
||||
DIAG_START_DRIVER = 300,
|
||||
DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
|
||||
DIAG_START_LEX = DIAG_START_FRONTEND + 120,
|
||||
DIAG_START_PARSE = DIAG_START_LEX + 300,
|
||||
DIAG_START_AST = DIAG_START_PARSE + 300,
|
||||
DIAG_START_SEMA = DIAG_START_AST + 100,
|
||||
DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000,
|
||||
DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
|
||||
};
|
||||
|
||||
class CustomDiagInfo;
|
||||
|
||||
/// diag::kind - All of the diagnostics that can be emitted by the frontend.
|
||||
typedef unsigned kind;
|
||||
|
||||
// Get typedefs for common diagnostics.
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
|
||||
#include "clang/Basic/DiagnosticCommonKinds.inc"
|
||||
NUM_BUILTIN_COMMON_DIAGNOSTICS
|
||||
#undef DIAG
|
||||
};
|
||||
|
||||
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
||||
/// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR
|
||||
/// (emit as an error). It allows clients to map errors to
|
||||
/// MAP_ERROR/MAP_DEFAULT or MAP_FATAL (stop emitting diagnostics after this
|
||||
/// one).
|
||||
enum Mapping {
|
||||
// NOTE: 0 means "uncomputed".
|
||||
MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it.
|
||||
MAP_WARNING = 2, //< Map this diagnostic to a warning.
|
||||
MAP_ERROR = 3, //< Map this diagnostic to an error.
|
||||
MAP_FATAL = 4, //< Map this diagnostic to a fatal error.
|
||||
|
||||
/// Map this diagnostic to "warning", but make it immune to -Werror. This
|
||||
/// happens when you specify -Wno-error=foo.
|
||||
MAP_WARNING_NO_WERROR = 5,
|
||||
/// Map this diagnostic to "error", but make it immune to -Wfatal-errors.
|
||||
/// This happens for -Wno-fatal-errors=foo.
|
||||
MAP_ERROR_NO_WFATAL = 6
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Used for handling and querying diagnostic IDs. Can be used and shared
|
||||
/// by multiple Diagnostics for multiple translation units.
|
||||
class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> {
|
||||
public:
|
||||
/// Level - The level of the diagnostic, after it has been through mapping.
|
||||
enum Level {
|
||||
Ignored, Note, Warning, Error, Fatal
|
||||
};
|
||||
|
||||
private:
|
||||
/// CustomDiagInfo - Information for uniquing and looking up custom diags.
|
||||
diag::CustomDiagInfo *CustomDiagInfo;
|
||||
|
||||
public:
|
||||
DiagnosticIDs();
|
||||
~DiagnosticIDs();
|
||||
|
||||
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
|
||||
/// and level. If this is the first request for this diagnosic, it is
|
||||
/// registered and created, otherwise the existing ID is returned.
|
||||
unsigned getCustomDiagID(Level L, llvm::StringRef Message);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic classification and reporting interfaces.
|
||||
//
|
||||
|
||||
/// getDescription - Given a diagnostic ID, return a description of the
|
||||
/// issue.
|
||||
const char *getDescription(unsigned DiagID) const;
|
||||
|
||||
/// isNoteWarningOrExtension - Return true if the unmapped diagnostic
|
||||
/// level of the specified diagnostic ID is a Warning or Extension.
|
||||
/// This only works on builtin diagnostics, not custom ones, and is not legal to
|
||||
/// call on NOTEs.
|
||||
static bool isBuiltinWarningOrExtension(unsigned DiagID);
|
||||
|
||||
/// \brief Determine whether the given built-in diagnostic ID is a
|
||||
/// Note.
|
||||
static bool isBuiltinNote(unsigned DiagID);
|
||||
|
||||
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
|
||||
/// ID is for an extension of some sort.
|
||||
///
|
||||
static bool isBuiltinExtensionDiag(unsigned DiagID) {
|
||||
bool ignored;
|
||||
return isBuiltinExtensionDiag(DiagID, ignored);
|
||||
}
|
||||
|
||||
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
|
||||
/// ID is for an extension of some sort. This also returns EnabledByDefault,
|
||||
/// which is set to indicate whether the diagnostic is ignored by default (in
|
||||
/// which case -pedantic enables it) or treated as a warning/error by default.
|
||||
///
|
||||
static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault);
|
||||
|
||||
|
||||
/// getWarningOptionForDiag - Return the lowest-level warning option that
|
||||
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
|
||||
/// the diagnostic, this returns null.
|
||||
static const char *getWarningOptionForDiag(unsigned DiagID);
|
||||
|
||||
/// getWarningOptionForDiag - Return the category number that a specified
|
||||
/// DiagID belongs to, or 0 if no category.
|
||||
static unsigned getCategoryNumberForDiag(unsigned DiagID);
|
||||
|
||||
/// getCategoryNameFromID - Given a category ID, return the name of the
|
||||
/// category.
|
||||
static const char *getCategoryNameFromID(unsigned CategoryID);
|
||||
|
||||
/// \brief Enumeration describing how the the emission of a diagnostic should
|
||||
/// be treated when it occurs during C++ template argument deduction.
|
||||
enum SFINAEResponse {
|
||||
/// \brief The diagnostic should not be reported, but it should cause
|
||||
/// template argument deduction to fail.
|
||||
///
|
||||
/// The vast majority of errors that occur during template argument
|
||||
/// deduction fall into this category.
|
||||
SFINAE_SubstitutionFailure,
|
||||
|
||||
/// \brief The diagnostic should be suppressed entirely.
|
||||
///
|
||||
/// Warnings generally fall into this category.
|
||||
SFINAE_Suppress,
|
||||
|
||||
/// \brief The diagnostic should be reported.
|
||||
///
|
||||
/// The diagnostic should be reported. Various fatal errors (e.g.,
|
||||
/// template instantiation depth exceeded) fall into this category.
|
||||
SFINAE_Report,
|
||||
|
||||
/// \brief The diagnostic is an access-control diagnostic, which will be
|
||||
/// substitution failures in some contexts and reported in others.
|
||||
SFINAE_AccessControl
|
||||
};
|
||||
|
||||
/// \brief Determines whether the given built-in diagnostic ID is
|
||||
/// for an error that is suppressed if it occurs during C++ template
|
||||
/// argument deduction.
|
||||
///
|
||||
/// When an error is suppressed due to SFINAE, the template argument
|
||||
/// deduction fails but no diagnostic is emitted. Certain classes of
|
||||
/// errors, such as those errors that involve C++ access control,
|
||||
/// are not SFINAE errors.
|
||||
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
|
||||
|
||||
private:
|
||||
/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
|
||||
/// "unknown-pragmas" to have the specified mapping. This returns true and
|
||||
/// ignores the request if "Group" was unknown, false otherwise.
|
||||
bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map,
|
||||
SourceLocation Loc, Diagnostic &Diag) const;
|
||||
|
||||
/// \brief Based on the way the client configured the Diagnostic
|
||||
/// object, classify the specified diagnostic ID into a Level, consumable by
|
||||
/// the DiagnosticClient.
|
||||
///
|
||||
/// \param Loc The source location we are interested in finding out the
|
||||
/// diagnostic state. Can be null in order to query the latest state.
|
||||
DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
|
||||
const Diagnostic &Diag) const;
|
||||
|
||||
/// getDiagnosticLevel - This is an internal implementation helper used when
|
||||
/// DiagClass is already known.
|
||||
DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID,
|
||||
unsigned DiagClass,
|
||||
SourceLocation Loc,
|
||||
const Diagnostic &Diag) const;
|
||||
|
||||
/// ProcessDiag - This is the method used to report a diagnostic that is
|
||||
/// finally fully formed.
|
||||
///
|
||||
/// \returns true if the diagnostic was emitted, false if it was
|
||||
/// suppressed.
|
||||
bool ProcessDiag(Diagnostic &Diag) const;
|
||||
|
||||
friend class Diagnostic;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -45,8 +45,8 @@ def charize_microsoft_ext : Extension<"@# is a microsoft extension">;
|
||||
|
||||
def ext_token_used : Extension<"extension used">;
|
||||
|
||||
def err_unterminated_string : Error<"missing terminating '\"' character">;
|
||||
def err_unterminated_char : Error<"missing terminating ' character">;
|
||||
def warn_unterminated_string : ExtWarn<"missing terminating '\"' character">;
|
||||
def warn_unterminated_char : ExtWarn<"missing terminating ' character">;
|
||||
def err_empty_character : Error<"empty character constant">;
|
||||
def err_unterminated_block_comment : Error<"unterminated /* comment">;
|
||||
def err_invalid_character_to_charify : Error<
|
||||
@ -98,6 +98,10 @@ def warn_hex_escape_too_large : ExtWarn<"hex escape sequence out of range">;
|
||||
def ext_string_too_long : Extension<"string literal of length %0 exceeds "
|
||||
"maximum length %1 that %select{C90|ISO C99|C++}2 compilers are required to "
|
||||
"support">, InGroup<OverlengthStrings>;
|
||||
def warn_ucn_escape_too_large : ExtWarn<
|
||||
"character unicode escape sequence too long for its type">;
|
||||
def warn_ucn_not_valid_in_c89 : ExtWarn<
|
||||
"unicode escape sequences are only valid in C99 or C++">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PTH Diagnostics
|
||||
@ -240,11 +244,11 @@ def warn_pragma_ignored : Warning<"unknown pragma ignored">,
|
||||
InGroup<UnknownPragmas>, DefaultIgnore;
|
||||
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
|
||||
InGroup<UnknownPragmas>;
|
||||
def ext_stdc_pragma_syntax :
|
||||
def ext_on_off_switch_syntax :
|
||||
ExtWarn<"expected 'ON' or 'OFF' or 'DEFAULT' in pragma">,
|
||||
InGroup<UnknownPragmas>;
|
||||
def ext_stdc_pragma_syntax_eom :
|
||||
ExtWarn<"expected end of macro in STDC pragma">,
|
||||
def ext_pragma_syntax_eom :
|
||||
ExtWarn<"expected end of macro in pragma">,
|
||||
InGroup<UnknownPragmas>;
|
||||
def warn_stdc_fenv_access_not_supported :
|
||||
Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">,
|
||||
|
@ -55,11 +55,15 @@ def ext_c99_compound_literal : Extension<
|
||||
def ext_enumerator_list_comma : Extension<
|
||||
"commas at the end of enumerator lists are a %select{C99|C++0x}0-specific "
|
||||
"feature">;
|
||||
def err_enumerator_list_missing_comma : Error<
|
||||
"missing ',' between enumerators">;
|
||||
|
||||
def ext_gnu_indirect_goto : Extension<
|
||||
"use of GNU indirect-goto extension">, InGroup<GNU>;
|
||||
def ext_gnu_address_of_label : Extension<
|
||||
"use of GNU address-of-label extension">, InGroup<GNU>;
|
||||
def ext_gnu_local_label : Extension<
|
||||
"use of GNU locally declared label extension">, InGroup<GNU>;
|
||||
def ext_gnu_statement_expr : Extension<
|
||||
"use of GNU statement expression extension">, InGroup<GNU>;
|
||||
def ext_gnu_conditional_expr : Extension<
|
||||
@ -93,6 +97,7 @@ def err_expected_lsquare : Error<"expected '['">;
|
||||
def err_expected_rsquare : Error<"expected ']'">;
|
||||
def err_expected_rbrace : Error<"expected '}'">;
|
||||
def err_expected_greater : Error<"expected '>'">;
|
||||
def err_expected_ggg : Error<"expected '>>>'">;
|
||||
def err_expected_semi_declaration : Error<
|
||||
"expected ';' at end of declaration">;
|
||||
def err_expected_semi_decl_list : Error<
|
||||
@ -110,6 +115,8 @@ def err_expected_fn_body : Error<
|
||||
def err_expected_method_body : Error<"expected method body">;
|
||||
def err_invalid_token_after_toplevel_declarator : Error<
|
||||
"expected ';' after top level declarator">;
|
||||
def err_invalid_equalequal_after_declarator : Error<
|
||||
"invalid '==' at end of declaration; did you mean '='?">;
|
||||
def err_expected_statement : Error<"expected statement">;
|
||||
def err_expected_lparen_after : Error<"expected '(' after '%0'">;
|
||||
def err_expected_lparen_after_id : Error<"expected '(' after %0">;
|
||||
@ -122,6 +129,8 @@ def err_expected_while : Error<"expected 'while' in do/while loop">;
|
||||
def err_expected_semi_after : Error<"expected ';' after %0">;
|
||||
def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">;
|
||||
def err_expected_semi_after_expr : Error<"expected ';' after expression">;
|
||||
def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">;
|
||||
|
||||
def err_expected_semi_after_method_proto : Error<
|
||||
"expected ';' after method prototype">;
|
||||
def err_expected_semi_after_namespace_name : Error<
|
||||
@ -139,6 +148,8 @@ def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">;
|
||||
def err_expected_colon_after : Error<"expected ':' after %0">;
|
||||
def err_label_end_of_compound_statement : Error<
|
||||
"label at end of compound statement: expected statement">;
|
||||
def err_address_of_label_outside_fn : Error<
|
||||
"use of address-of-label extension outside of a function body">;
|
||||
def err_expected_string_literal : Error<"expected string literal">;
|
||||
def err_expected_asm_operand : Error<
|
||||
"expected string literal or '[' for asm operand">, CatInlineAsm;
|
||||
@ -152,10 +163,12 @@ def err_invalid_reference_qualifier_application : Error<
|
||||
"'%0' qualifier may not be applied to a reference">;
|
||||
def err_illegal_decl_reference_to_reference : Error<
|
||||
"%0 declared as a reference to a reference">;
|
||||
def err_rvalue_reference : Error<
|
||||
"rvalue references are only allowed in C++0x">;
|
||||
def ext_inline_namespace : Extension<
|
||||
"inline namespaces are a C++0x feature">;
|
||||
def ext_rvalue_reference : ExtWarn<
|
||||
"rvalue references are a C++0x extension">, InGroup<CXX0x>;
|
||||
def ext_ref_qualifier : ExtWarn<
|
||||
"reference qualifiers on functions are a C++0x extension">, InGroup<CXX0x>;
|
||||
def ext_inline_namespace : ExtWarn<
|
||||
"inline namespaces are a C++0x feature">, InGroup<CXX0x>;
|
||||
def err_argument_required_after_attribute : Error<
|
||||
"argument required after attribute">;
|
||||
def err_missing_param : Error<"expected parameter declarator">;
|
||||
@ -194,10 +207,16 @@ def err_unknown_typename : Error<
|
||||
"unknown type name %0">;
|
||||
def err_use_of_tag_name_without_tag : Error<
|
||||
"must use '%1' tag to refer to type %0%select{| in this scope}2">;
|
||||
def err_templated_using_directive : Error<
|
||||
"cannot template a using directive">;
|
||||
def err_templated_using_declaration : Error<
|
||||
"cannot template a using declaration">;
|
||||
def err_expected_ident_in_using : Error<
|
||||
"expected an identifier in using directive">;
|
||||
def err_unexected_colon_in_nested_name_spec : Error<
|
||||
"unexpected ':' in nested name specifier">;
|
||||
def err_bool_redeclaration : Error<
|
||||
"redeclaration of C++ built-in type 'bool'">;
|
||||
|
||||
/// Objective-C parser diagnostics
|
||||
def err_expected_minus_or_plus : Error<
|
||||
@ -214,13 +233,17 @@ def err_illegal_super_cast : Error<
|
||||
def err_objc_illegal_visibility_spec : Error<
|
||||
"illegal visibility specification">;
|
||||
def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">;
|
||||
def err_objc_expected_equal : Error<
|
||||
"setter/getter expects '=' followed by name">;
|
||||
def err_objc_expected_equal_for_getter : Error<
|
||||
"expected '=' for Objective-C getter">;
|
||||
def err_objc_expected_equal_for_setter : Error<
|
||||
"expected '=' for Objective-C setter">;
|
||||
def err_objc_expected_selector_for_getter_setter : Error<
|
||||
"expected selector for Objective-C %select{setter|getter}0">;
|
||||
def err_objc_property_requires_field_name : Error<
|
||||
"property requires fields to be named">;
|
||||
def err_objc_property_bitfield : Error<"property name cannot be a bitfield">;
|
||||
def err_objc_expected_property_attr : Error<"unknown property attribute %0">;
|
||||
def err_objc_propertoes_require_objc2 : Error<
|
||||
def err_objc_properties_require_objc2 : Error<
|
||||
"properties are an Objective-C 2 feature">;
|
||||
def err_objc_unexpected_attr : Error<
|
||||
"prefix attribute must be followed by an interface or protocol">;
|
||||
@ -283,8 +306,6 @@ def err_default_arg_unparsed : Error<
|
||||
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
|
||||
|
||||
// C++ operator overloading
|
||||
def err_operator_missing_type_specifier : Error<
|
||||
"missing type specifier after 'operator'">;
|
||||
def err_operator_string_not_empty : Error<
|
||||
"string literal after 'operator' must be '\"\"'">;
|
||||
|
||||
@ -334,6 +355,10 @@ def err_enum_template : Error<"enumeration cannot be a template">;
|
||||
def err_missing_dependent_template_keyword : Error<
|
||||
"use 'template' keyword to treat '%0' as a dependent template name">;
|
||||
|
||||
def warn_static_inline_explicit_inst_ignored : Warning<
|
||||
"ignoring '%select{static|inline}0' keyword on explicit template "
|
||||
"instantiation">;
|
||||
|
||||
// Constructor template diagnostics.
|
||||
def err_out_of_line_constructor_template_id : Error<
|
||||
"out-of-line constructor for %0 cannot have template arguments">;
|
||||
@ -356,18 +381,42 @@ def err_expected_type_name_after_typename : Error<
|
||||
def err_explicit_spec_non_template : Error<
|
||||
"explicit %select{specialization|instantiation}0 of non-template "
|
||||
"%select{class|struct|union}1 %2">;
|
||||
|
||||
def err_variadic_templates : Error<
|
||||
"variadic templates are only allowed in C++0x">;
|
||||
|
||||
def err_default_template_template_parameter_not_template : Error<
|
||||
"default template argument for a template template parameter must be a class "
|
||||
"template">;
|
||||
|
||||
def err_ctor_init_missing_comma : Error<
|
||||
"missing ',' between base or member initializers">;
|
||||
|
||||
// C++ declarations
|
||||
def err_friend_decl_defines_class : Error<
|
||||
"cannot define a type in a friend declaration">;
|
||||
|
||||
|
||||
def warn_deleted_function_accepted_as_extension: ExtWarn<
|
||||
"deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>;
|
||||
|
||||
// C++0x override control
|
||||
def ext_override_control_keyword : Extension<
|
||||
"'%0' keyword accepted as a C++0x extension">, InGroup<CXX0x>;
|
||||
def ext_override_inline: Extension<
|
||||
"'%0' keyword only allowed in declarations, allowed as an extension">;
|
||||
|
||||
def err_duplicate_virt_specifier : Error<
|
||||
"class member already marked '%0'">;
|
||||
def err_duplicate_class_virt_specifier : Error<
|
||||
"class already marked '%0'">;
|
||||
|
||||
def err_scoped_enum_missing_identifier : Error<
|
||||
"scoped enumeration requires a name">;
|
||||
|
||||
def err_expected_parameter_pack : Error<
|
||||
"expected the name of a parameter pack">;
|
||||
def err_paren_sizeof_parameter_pack : Error<
|
||||
"missing parentheses around the size of parameter pack %0">;
|
||||
def err_sizeof_parameter_pack : Error<
|
||||
"expected parenthesized parameter pack name in 'sizeof...' expression">;
|
||||
|
||||
// Language specific pragmas
|
||||
// - Generic warnings
|
||||
def warn_pragma_expected_lparen : Warning<
|
||||
@ -398,5 +447,17 @@ def warn_pragma_unused_expected_var : Warning<
|
||||
def warn_pragma_unused_expected_punc : Warning<
|
||||
"expected ')' or ',' in '#pragma unused'">;
|
||||
|
||||
// OpenCL Section 6.8.g
|
||||
def err_not_opencl_storage_class_specifier : Error<
|
||||
"OpenCL does not support the '%0' storage class specifier">;
|
||||
|
||||
// OpenCL EXTENSION pragma (OpenCL 1.1 [9.1])
|
||||
def warn_pragma_expected_colon : Warning<
|
||||
"missing ':' after %0 - ignoring">;
|
||||
def warn_pragma_expected_enable_disable : Warning<
|
||||
"expected 'enable' or 'disable' - ignoring">;
|
||||
def warn_pragma_unknown_extension : Warning<
|
||||
"unknown OpenCL extension %0 - ignoring">;
|
||||
|
||||
} // end of Parse Issue category.
|
||||
} // end of Parser diagnostics
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@
|
||||
#ifndef LLVM_CLANG_FILEMANAGER_H
|
||||
#define LLVM_CLANG_FILEMANAGER_H
|
||||
|
||||
#include "clang/Basic/FileSystemOptions.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
@ -22,12 +23,20 @@
|
||||
#include "llvm/Config/config.h" // for mode_t
|
||||
// FIXME: Enhance libsystem to support inode and other fields in stat.
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
struct stat;
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
namespace sys { class Path; }
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class FileManager;
|
||||
|
||||
/// DirectoryEntry - Cached information about one directory on the disk.
|
||||
class FileSystemStatCache;
|
||||
|
||||
/// DirectoryEntry - Cached information about one directory (either on
|
||||
/// the disk or in the virtual file system).
|
||||
///
|
||||
class DirectoryEntry {
|
||||
const char *Name; // Name of the directory.
|
||||
@ -37,7 +46,9 @@ class DirectoryEntry {
|
||||
const char *getName() const { return Name; }
|
||||
};
|
||||
|
||||
/// FileEntry - Cached information about one file on the disk.
|
||||
/// FileEntry - Cached information about one file (either on the disk
|
||||
/// or in the virtual file system). If the 'FD' member is valid, then
|
||||
/// this FileEntry has an open file descriptor for the file.
|
||||
///
|
||||
class FileEntry {
|
||||
const char *Name; // Name of the file.
|
||||
@ -48,12 +59,29 @@ class FileEntry {
|
||||
dev_t Device; // ID for the device containing the file.
|
||||
ino_t Inode; // Inode number for the file.
|
||||
mode_t FileMode; // The file mode as returned by 'stat'.
|
||||
|
||||
/// FD - The file descriptor for the file entry if it is opened and owned
|
||||
/// by the FileEntry. If not, this is set to -1.
|
||||
mutable int FD;
|
||||
friend class FileManager;
|
||||
|
||||
public:
|
||||
FileEntry(dev_t device, ino_t inode, mode_t m)
|
||||
: Name(0), Device(device), Inode(inode), FileMode(m) {}
|
||||
: Name(0), Device(device), Inode(inode), FileMode(m), FD(-1) {}
|
||||
// Add a default constructor for use with llvm::StringMap
|
||||
FileEntry() : Name(0), Device(0), Inode(0), FileMode(0) {}
|
||||
FileEntry() : Name(0), Device(0), Inode(0), FileMode(0), FD(-1) {}
|
||||
|
||||
FileEntry(const FileEntry &FE) {
|
||||
memcpy(this, &FE, sizeof(FE));
|
||||
assert(FD == -1 && "Cannot copy a file-owning FileEntry");
|
||||
}
|
||||
|
||||
void operator=(const FileEntry &FE) {
|
||||
memcpy(this, &FE, sizeof(FE));
|
||||
assert(FD == -1 && "Cannot assign a file-owning FileEntry");
|
||||
}
|
||||
|
||||
~FileEntry();
|
||||
|
||||
const char *getName() const { return Name; }
|
||||
off_t getSize() const { return Size; }
|
||||
@ -67,111 +95,68 @@ class FileEntry {
|
||||
///
|
||||
const DirectoryEntry *getDir() const { return Dir; }
|
||||
|
||||
bool operator<(const FileEntry& RHS) const {
|
||||
bool operator<(const FileEntry &RHS) const {
|
||||
return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Abstract interface for introducing a FileManager cache for 'stat'
|
||||
/// system calls, which is used by precompiled and pretokenized headers to
|
||||
/// improve performance.
|
||||
class StatSysCallCache {
|
||||
protected:
|
||||
llvm::OwningPtr<StatSysCallCache> NextStatCache;
|
||||
|
||||
public:
|
||||
virtual ~StatSysCallCache() {}
|
||||
virtual int stat(const char *path, struct stat *buf) {
|
||||
if (getNextStatCache())
|
||||
return getNextStatCache()->stat(path, buf);
|
||||
|
||||
return ::stat(path, buf);
|
||||
}
|
||||
|
||||
/// \brief Sets the next stat call cache in the chain of stat caches.
|
||||
/// Takes ownership of the given stat cache.
|
||||
void setNextStatCache(StatSysCallCache *Cache) {
|
||||
NextStatCache.reset(Cache);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the next stat call cache in the chain.
|
||||
StatSysCallCache *getNextStatCache() { return NextStatCache.get(); }
|
||||
|
||||
/// \brief Retrieve the next stat call cache in the chain, transferring
|
||||
/// ownership of this cache (and, transitively, all of the remaining caches)
|
||||
/// to the caller.
|
||||
StatSysCallCache *takeNextStatCache() { return NextStatCache.take(); }
|
||||
};
|
||||
|
||||
/// \brief A stat "cache" that can be used by FileManager to keep
|
||||
/// track of the results of stat() calls that occur throughout the
|
||||
/// execution of the front end.
|
||||
class MemorizeStatCalls : public StatSysCallCache {
|
||||
public:
|
||||
/// \brief The result of a stat() call.
|
||||
///
|
||||
/// The first member is the result of calling stat(). If stat()
|
||||
/// found something, the second member is a copy of the stat
|
||||
/// structure.
|
||||
typedef std::pair<int, struct stat> StatResult;
|
||||
|
||||
/// \brief The set of stat() calls that have been
|
||||
llvm::StringMap<StatResult, llvm::BumpPtrAllocator> StatCalls;
|
||||
|
||||
typedef llvm::StringMap<StatResult, llvm::BumpPtrAllocator>::const_iterator
|
||||
iterator;
|
||||
|
||||
iterator begin() const { return StatCalls.begin(); }
|
||||
iterator end() const { return StatCalls.end(); }
|
||||
|
||||
virtual int stat(const char *path, struct stat *buf);
|
||||
};
|
||||
|
||||
/// FileManager - Implements support for file system lookup, file system
|
||||
/// caching, and directory search management. This also handles more advanced
|
||||
/// properties, such as uniquing files based on "inode", so that a file with two
|
||||
/// names (e.g. symlinked) will be treated as a single file.
|
||||
///
|
||||
class FileManager {
|
||||
FileSystemOptions FileSystemOpts;
|
||||
|
||||
class UniqueDirContainer;
|
||||
class UniqueFileContainer;
|
||||
|
||||
/// UniqueDirs/UniqueFiles - Cache for existing directories/files.
|
||||
/// UniqueRealDirs/UniqueRealFiles - Cache for existing real directories/files.
|
||||
///
|
||||
UniqueDirContainer &UniqueDirs;
|
||||
UniqueFileContainer &UniqueFiles;
|
||||
UniqueDirContainer &UniqueRealDirs;
|
||||
UniqueFileContainer &UniqueRealFiles;
|
||||
|
||||
/// DirEntries/FileEntries - This is a cache of directory/file entries we have
|
||||
/// looked up. The actual Entry is owned by UniqueFiles/UniqueDirs above.
|
||||
/// \brief The virtual directories that we have allocated. For each
|
||||
/// virtual file (e.g. foo/bar/baz.cpp), we add all of its parent
|
||||
/// directories (foo/ and foo/bar/) here.
|
||||
llvm::SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries;
|
||||
/// \brief The virtual files that we have allocated.
|
||||
llvm::SmallVector<FileEntry*, 4> VirtualFileEntries;
|
||||
|
||||
/// SeenDirEntries/SeenFileEntries - This is a cache that maps paths
|
||||
/// to directory/file entries (either real or virtual) we have
|
||||
/// looked up. The actual Entries for real directories/files are
|
||||
/// owned by UniqueRealDirs/UniqueRealFiles above, while the Entries
|
||||
/// for virtual directories/files are owned by
|
||||
/// VirtualDirectoryEntries/VirtualFileEntries above.
|
||||
///
|
||||
llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> DirEntries;
|
||||
llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> FileEntries;
|
||||
llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> SeenDirEntries;
|
||||
llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries;
|
||||
|
||||
/// NextFileUID - Each FileEntry we create is assigned a unique ID #.
|
||||
///
|
||||
unsigned NextFileUID;
|
||||
|
||||
/// \brief The virtual files that we have allocated.
|
||||
llvm::SmallVector<FileEntry *, 4> VirtualFileEntries;
|
||||
|
||||
// Statistics.
|
||||
unsigned NumDirLookups, NumFileLookups;
|
||||
unsigned NumDirCacheMisses, NumFileCacheMisses;
|
||||
|
||||
// Caching.
|
||||
llvm::OwningPtr<StatSysCallCache> StatCache;
|
||||
llvm::OwningPtr<FileSystemStatCache> StatCache;
|
||||
|
||||
int stat_cached(const char* path, struct stat* buf) {
|
||||
return StatCache.get() ? StatCache->stat(path, buf) : stat(path, buf);
|
||||
}
|
||||
bool getStatValue(const char *Path, struct stat &StatBuf,
|
||||
int *FileDescriptor);
|
||||
|
||||
/// Add all ancestors of the given path (pointing to either a file
|
||||
/// or a directory) as virtual directories.
|
||||
void addAncestorsAsVirtualDirs(llvm::StringRef Path);
|
||||
|
||||
public:
|
||||
FileManager();
|
||||
FileManager(const FileSystemOptions &FileSystemOpts);
|
||||
~FileManager();
|
||||
|
||||
/// \brief Installs the provided StatSysCallCache object within
|
||||
/// the FileManager.
|
||||
/// \brief Installs the provided FileSystemStatCache object within
|
||||
/// the FileManager.
|
||||
///
|
||||
/// Ownership of this object is transferred to the FileManager.
|
||||
///
|
||||
@ -181,33 +166,46 @@ class FileManager {
|
||||
/// \param AtBeginning whether this new stat cache must be installed at the
|
||||
/// beginning of the chain of stat caches. Otherwise, it will be added to
|
||||
/// the end of the chain.
|
||||
void addStatCache(StatSysCallCache *statCache, bool AtBeginning = false);
|
||||
void addStatCache(FileSystemStatCache *statCache, bool AtBeginning = false);
|
||||
|
||||
/// \brief Removes the provided StatSysCallCache object from the file manager.
|
||||
void removeStatCache(StatSysCallCache *statCache);
|
||||
|
||||
/// getDirectory - Lookup, cache, and verify the specified directory. This
|
||||
/// returns null if the directory doesn't exist.
|
||||
///
|
||||
const DirectoryEntry *getDirectory(llvm::StringRef Filename) {
|
||||
return getDirectory(Filename.begin(), Filename.end());
|
||||
}
|
||||
const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd);
|
||||
/// \brief Removes the specified FileSystemStatCache object from the manager.
|
||||
void removeStatCache(FileSystemStatCache *statCache);
|
||||
|
||||
/// getFile - Lookup, cache, and verify the specified file. This returns null
|
||||
/// if the file doesn't exist.
|
||||
/// getDirectory - Lookup, cache, and verify the specified directory
|
||||
/// (real or virtual). This returns NULL if the directory doesn't exist.
|
||||
///
|
||||
const FileEntry *getFile(llvm::StringRef Filename) {
|
||||
return getFile(Filename.begin(), Filename.end());
|
||||
}
|
||||
const FileEntry *getFile(const char *FilenameStart,
|
||||
const char *FilenameEnd);
|
||||
const DirectoryEntry *getDirectory(llvm::StringRef DirName);
|
||||
|
||||
/// getFile - Lookup, cache, and verify the specified file (real or
|
||||
/// virtual). This returns NULL if the file doesn't exist.
|
||||
///
|
||||
const FileEntry *getFile(llvm::StringRef Filename);
|
||||
|
||||
/// \brief Retrieve a file entry for a "virtual" file that acts as
|
||||
/// if there were a file with the given name on disk. The file
|
||||
/// itself is not accessed.
|
||||
const FileEntry *getVirtualFile(llvm::StringRef Filename, off_t Size,
|
||||
time_t ModificationTime);
|
||||
|
||||
/// \brief Open the specified file as a MemoryBuffer, returning a new
|
||||
/// MemoryBuffer if successful, otherwise returning null.
|
||||
llvm::MemoryBuffer *getBufferForFile(const FileEntry *Entry,
|
||||
std::string *ErrorStr = 0);
|
||||
llvm::MemoryBuffer *getBufferForFile(llvm::StringRef Filename,
|
||||
std::string *ErrorStr = 0);
|
||||
|
||||
/// \brief If path is not absolute and FileSystemOptions set the working
|
||||
/// directory, the path is modified to be relative to the given
|
||||
/// working directory.
|
||||
static void FixupRelativePath(llvm::sys::Path &path,
|
||||
const FileSystemOptions &FSOpts);
|
||||
|
||||
|
||||
/// \brief Produce an array mapping from the unique IDs assigned to each
|
||||
/// file to the corresponding FileEntry pointer.
|
||||
void GetUniqueIDMapping(
|
||||
llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const;
|
||||
|
||||
void PrintStats() const;
|
||||
};
|
||||
|
||||
|
31
include/clang/Basic/FileSystemOptions.h
Normal file
31
include/clang/Basic/FileSystemOptions.h
Normal file
@ -0,0 +1,31 @@
|
||||
//===--- FileSystemOptions.h - File System Options --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the FileSystemOptions interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H
|
||||
#define LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief Keeps track of options that affect how file operations are performed.
|
||||
class FileSystemOptions {
|
||||
public:
|
||||
/// \brief If set, paths are resolved as if the working directory was
|
||||
/// set to the value of WorkingDir.
|
||||
std::string WorkingDir;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
101
include/clang/Basic/FileSystemStatCache.h
Normal file
101
include/clang/Basic/FileSystemStatCache.h
Normal file
@ -0,0 +1,101 @@
|
||||
//===--- FileSystemStatCache.h - Caching for 'stat' calls -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the FileSystemStatCache interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_FILESYSTEMSTATCACHE_H
|
||||
#define LLVM_CLANG_FILESYSTEMSTATCACHE_H
|
||||
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief Abstract interface for introducing a FileManager cache for 'stat'
|
||||
/// system calls, which is used by precompiled and pretokenized headers to
|
||||
/// improve performance.
|
||||
class FileSystemStatCache {
|
||||
protected:
|
||||
llvm::OwningPtr<FileSystemStatCache> NextStatCache;
|
||||
|
||||
public:
|
||||
virtual ~FileSystemStatCache() {}
|
||||
|
||||
enum LookupResult {
|
||||
CacheExists, //< We know the file exists and its cached stat data.
|
||||
CacheMissing //< We know that the file doesn't exist.
|
||||
};
|
||||
|
||||
/// FileSystemStatCache::get - Get the 'stat' information for the specified
|
||||
/// path, using the cache to accellerate it if possible. This returns true if
|
||||
/// the path does not exist or false if it exists.
|
||||
///
|
||||
/// If FileDescriptor is non-null, then this lookup should only return success
|
||||
/// for files (not directories). If it is null this lookup should only return
|
||||
/// success for directories (not files). On a successful file lookup, the
|
||||
/// implementation can optionally fill in FileDescriptor with a valid
|
||||
/// descriptor and the client guarantees that it will close it.
|
||||
static bool get(const char *Path, struct stat &StatBuf, int *FileDescriptor,
|
||||
FileSystemStatCache *Cache);
|
||||
|
||||
|
||||
/// \brief Sets the next stat call cache in the chain of stat caches.
|
||||
/// Takes ownership of the given stat cache.
|
||||
void setNextStatCache(FileSystemStatCache *Cache) {
|
||||
NextStatCache.reset(Cache);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the next stat call cache in the chain.
|
||||
FileSystemStatCache *getNextStatCache() { return NextStatCache.get(); }
|
||||
|
||||
/// \brief Retrieve the next stat call cache in the chain, transferring
|
||||
/// ownership of this cache (and, transitively, all of the remaining caches)
|
||||
/// to the caller.
|
||||
FileSystemStatCache *takeNextStatCache() { return NextStatCache.take(); }
|
||||
|
||||
protected:
|
||||
virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
|
||||
int *FileDescriptor) = 0;
|
||||
|
||||
LookupResult statChained(const char *Path, struct stat &StatBuf,
|
||||
int *FileDescriptor) {
|
||||
if (FileSystemStatCache *Next = getNextStatCache())
|
||||
return Next->getStat(Path, StatBuf, FileDescriptor);
|
||||
|
||||
// If we hit the end of the list of stat caches to try, just compute and
|
||||
// return it without a cache.
|
||||
return get(Path, StatBuf, FileDescriptor, 0) ? CacheMissing : CacheExists;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A stat "cache" that can be used by FileManager to keep
|
||||
/// track of the results of stat() calls that occur throughout the
|
||||
/// execution of the front end.
|
||||
class MemorizeStatCalls : public FileSystemStatCache {
|
||||
public:
|
||||
/// \brief The set of stat() calls that have been seen.
|
||||
llvm::StringMap<struct stat, llvm::BumpPtrAllocator> StatCalls;
|
||||
|
||||
typedef llvm::StringMap<struct stat, llvm::BumpPtrAllocator>::const_iterator
|
||||
iterator;
|
||||
|
||||
iterator begin() const { return StatCalls.begin(); }
|
||||
iterator end() const { return StatCalls.end(); }
|
||||
|
||||
virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
|
||||
int *FileDescriptor);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user