mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-29 08:08:37 +00:00
Import Clang, at r72732.
This commit is contained in:
commit
ec2b103c26
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=193326 svn path=/vendor/clang/clang-r72732/; revision=193327; tag=vendor/clang/clang-r72732
56
CMakeLists.txt
Normal file
56
CMakeLists.txt
Normal file
@ -0,0 +1,56 @@
|
||||
macro(add_clang_library name)
|
||||
set(srcs ${ARGN})
|
||||
if(MSVC_IDE OR XCODE)
|
||||
file( GLOB_RECURSE headers *.h)
|
||||
set(srcs ${srcs} ${headers})
|
||||
string( REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list( GET split_path -1 dir)
|
||||
file( GLOB_RECURSE headers ../../include/clang${dir}/*.h)
|
||||
set(srcs ${srcs} ${headers})
|
||||
endif(MSVC_IDE OR XCODE)
|
||||
add_library( ${name} ${srcs} )
|
||||
if( LLVM_COMMON_DEPENDS )
|
||||
add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} )
|
||||
endif( LLVM_COMMON_DEPENDS )
|
||||
add_dependencies(${name} ClangDiagnosticCommon)
|
||||
if(MSVC)
|
||||
get_target_property(cflag ${name} COMPILE_FLAGS)
|
||||
if(NOT cflag)
|
||||
set(cflag "")
|
||||
endif(NOT cflag)
|
||||
set(cflag "${cflag} /Za")
|
||||
set_target_properties(${name} PROPERTIES COMPILE_FLAGS ${cflag})
|
||||
endif(MSVC)
|
||||
install(TARGETS ${name}
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib)
|
||||
endmacro(add_clang_library)
|
||||
|
||||
macro(add_clang_executable name)
|
||||
set(srcs ${ARGN})
|
||||
if(MSVC_IDE)
|
||||
file( GLOB_RECURSE headers *.h)
|
||||
set(srcs ${srcs} ${headers})
|
||||
endif(MSVC_IDE)
|
||||
add_llvm_executable( ${name} ${srcs} )
|
||||
install(TARGETS ${name}
|
||||
RUNTIME DESTINATION bin)
|
||||
endmacro(add_clang_executable)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include
|
||||
)
|
||||
|
||||
install(DIRECTORY include
|
||||
DESTINATION .
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(tools)
|
||||
|
||||
# TODO: docs.
|
2
INPUTS/Cocoa_h.m
Normal file
2
INPUTS/Cocoa_h.m
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
639
INPUTS/c99-intconst-1.c
Normal file
639
INPUTS/c99-intconst-1.c
Normal file
@ -0,0 +1,639 @@
|
||||
/* Test for integer constant types. */
|
||||
|
||||
/* Origin: Joseph Myers <jsm28@cam.ac.uk>. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* Assertion that constant C is of type T. */
|
||||
#define ASSERT_CONST_TYPE(C, T) \
|
||||
do { \
|
||||
typedef T type; \
|
||||
typedef type **typepp; \
|
||||
typedef __typeof__((C)) ctype; \
|
||||
typedef ctype **ctypepp; \
|
||||
typepp x = 0; \
|
||||
ctypepp y = 0; \
|
||||
x = y; \
|
||||
y = x; \
|
||||
} while (0)
|
||||
|
||||
/* (T *) if E is zero, (void *) otherwise. */
|
||||
#define type_if_not(T, E) __typeof__(0 ? (T *)0 : (void *)(E))
|
||||
|
||||
/* (T *) if E is nonzero, (void *) otherwise. */
|
||||
#define type_if(T, E) type_if_not(T, !(E))
|
||||
|
||||
/* Combine pointer types, all but one (void *). */
|
||||
#define type_comb2(T1, T2) __typeof__(0 ? (T1)0 : (T2)0)
|
||||
#define type_comb3(T1, T2, T3) type_comb2(T1, type_comb2(T2, T3))
|
||||
#define type_comb4(T1, T2, T3, T4) \
|
||||
type_comb2(T1, type_comb2(T2, type_comb2(T3, T4)))
|
||||
#define type_comb6(T1, T2, T3, T4, T5, T6) \
|
||||
type_comb2(T1, \
|
||||
type_comb2(T2, \
|
||||
type_comb2(T3, \
|
||||
type_comb2(T4, \
|
||||
type_comb2(T5, T6)))))
|
||||
|
||||
/* (T1 *) if E1, otherwise (T2 *) if E2. */
|
||||
#define first_of2p(T1, E1, T2, E2) type_comb2(type_if(T1, (E1)), \
|
||||
type_if(T2, (!(E1) && (E2))))
|
||||
/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3. */
|
||||
#define first_of3p(T1, E1, T2, E2, T3, E3) \
|
||||
type_comb3(type_if(T1, (E1)), \
|
||||
type_if(T2, (!(E1) && (E2))), \
|
||||
type_if(T3, (!(E1) && !(E2) && (E3))))
|
||||
/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3, otherwise
|
||||
(T4 *) if E4. */
|
||||
#define first_of4p(T1, E1, T2, E2, T3, E3, T4, E4) \
|
||||
type_comb4(type_if(T1, (E1)), \
|
||||
type_if(T2, (!(E1) && (E2))), \
|
||||
type_if(T3, (!(E1) && !(E2) && (E3))), \
|
||||
type_if(T4, (!(E1) && !(E2) && !(E3) && (E4))))
|
||||
/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3, otherwise
|
||||
(T4 *) if E4, otherwise (T5 *) if E5, otherwise (T6 *) if E6. */
|
||||
#define first_of6p(T1, E1, T2, E2, T3, E3, T4, E4, T5, E5, T6, E6) \
|
||||
type_comb6(type_if(T1, (E1)), \
|
||||
type_if(T2, (!(E1) && (E2))), \
|
||||
type_if(T3, (!(E1) && !(E2) && (E3))), \
|
||||
type_if(T4, (!(E1) && !(E2) && !(E3) && (E4))), \
|
||||
type_if(T5, (!(E1) && !(E2) && !(E3) && !(E4) && (E5))), \
|
||||
type_if(T6, (!(E1) && !(E2) && !(E3) \
|
||||
&& !(E4) && !(E5) && (E6))))
|
||||
|
||||
/* Likewise, but return the original type rather than a pointer type. */
|
||||
#define first_of2(T1, E1, T2, E2) \
|
||||
__typeof__(*((first_of2p(T1, (E1), T2, (E2)))0))
|
||||
#define first_of3(T1, E1, T2, E2, T3, E3) \
|
||||
__typeof__(*((first_of3p(T1, (E1), T2, (E2), T3, (E3)))0))
|
||||
#define first_of4(T1, E1, T2, E2, T3, E3, T4, E4) \
|
||||
__typeof__(*((first_of4p(T1, (E1), T2, (E2), T3, (E3), T4, (E4)))0))
|
||||
#define first_of6(T1, E1, T2, E2, T3, E3, T4, E4, T5, E5, T6, E6) \
|
||||
__typeof__(*((first_of6p(T1, (E1), T2, (E2), T3, (E3), \
|
||||
T4, (E4), T5, (E5), T6, (E6)))0))
|
||||
|
||||
/* Types of constants according to the C99 rules. */
|
||||
#define C99_UNSUF_DEC_TYPE(C) \
|
||||
first_of3(int, (C) <= INT_MAX, \
|
||||
long int, (C) <= LONG_MAX, \
|
||||
long long int, (C) <= LLONG_MAX)
|
||||
#define C99_UNSUF_OCTHEX_TYPE(C) \
|
||||
first_of6(int, (C) <= INT_MAX, \
|
||||
unsigned int, (C) <= UINT_MAX, \
|
||||
long int, (C) <= LONG_MAX, \
|
||||
unsigned long int, (C) <= ULONG_MAX, \
|
||||
long long int, (C) <= LLONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
#define C99_SUFu_TYPE(C) \
|
||||
first_of3(unsigned int, (C) <= UINT_MAX, \
|
||||
unsigned long int, (C) <= ULONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
#define C99_SUFl_DEC_TYPE(C) \
|
||||
first_of2(long int, (C) <= LONG_MAX, \
|
||||
long long int, (C) <= LLONG_MAX)
|
||||
#define C99_SUFl_OCTHEX_TYPE(C) \
|
||||
first_of4(long int, (C) <= LONG_MAX, \
|
||||
unsigned long int, (C) <= ULONG_MAX, \
|
||||
long long int, (C) <= LLONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
#define C99_SUFul_TYPE(C) \
|
||||
first_of2(unsigned long int, (C) <= ULONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
#define C99_SUFll_OCTHEX_TYPE(C) \
|
||||
first_of2(long long int, (C) <= LLONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
|
||||
/* Checks that constants have correct type. */
|
||||
#define CHECK_UNSUF_DEC_TYPE(C) ASSERT_CONST_TYPE((C), C99_UNSUF_DEC_TYPE((C)))
|
||||
#define CHECK_UNSUF_OCTHEX_TYPE(C) \
|
||||
ASSERT_CONST_TYPE((C), C99_UNSUF_OCTHEX_TYPE((C)))
|
||||
#define CHECK_SUFu_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFu_TYPE((C)))
|
||||
#define CHECK_SUFl_DEC_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFl_DEC_TYPE((C)))
|
||||
#define CHECK_SUFl_OCTHEX_TYPE(C) \
|
||||
ASSERT_CONST_TYPE((C), C99_SUFl_OCTHEX_TYPE((C)))
|
||||
#define CHECK_SUFul_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFul_TYPE((C)))
|
||||
#define CHECK_SUFll_DEC_TYPE(C) ASSERT_CONST_TYPE((C), long long int)
|
||||
#define CHECK_SUFll_OCTHEX_TYPE(C) \
|
||||
ASSERT_CONST_TYPE((C), C99_SUFll_OCTHEX_TYPE((C)))
|
||||
#define CHECK_SUFull_TYPE(C) ASSERT_CONST_TYPE((C), unsigned long long int)
|
||||
|
||||
/* Check a decimal value, with all suffixes. */
|
||||
#define CHECK_DEC_CONST(C) \
|
||||
CHECK_UNSUF_DEC_TYPE(C); \
|
||||
CHECK_SUFu_TYPE(C##u); \
|
||||
CHECK_SUFu_TYPE(C##U); \
|
||||
CHECK_SUFl_DEC_TYPE(C##l); \
|
||||
CHECK_SUFl_DEC_TYPE(C##L); \
|
||||
CHECK_SUFul_TYPE(C##ul); \
|
||||
CHECK_SUFul_TYPE(C##uL); \
|
||||
CHECK_SUFul_TYPE(C##Ul); \
|
||||
CHECK_SUFul_TYPE(C##UL); \
|
||||
CHECK_SUFll_DEC_TYPE(C##ll); \
|
||||
CHECK_SUFll_DEC_TYPE(C##LL); \
|
||||
CHECK_SUFull_TYPE(C##ull); \
|
||||
CHECK_SUFull_TYPE(C##uLL); \
|
||||
CHECK_SUFull_TYPE(C##Ull); \
|
||||
CHECK_SUFull_TYPE(C##ULL);
|
||||
|
||||
/* Check an octal or hexadecimal value, with all suffixes. */
|
||||
#define CHECK_OCTHEX_CONST(C) \
|
||||
CHECK_UNSUF_OCTHEX_TYPE(C); \
|
||||
CHECK_SUFu_TYPE(C##u); \
|
||||
CHECK_SUFu_TYPE(C##U); \
|
||||
CHECK_SUFl_OCTHEX_TYPE(C##l); \
|
||||
CHECK_SUFl_OCTHEX_TYPE(C##L); \
|
||||
CHECK_SUFul_TYPE(C##ul); \
|
||||
CHECK_SUFul_TYPE(C##uL); \
|
||||
CHECK_SUFul_TYPE(C##Ul); \
|
||||
CHECK_SUFul_TYPE(C##UL); \
|
||||
CHECK_SUFll_OCTHEX_TYPE(C##ll); \
|
||||
CHECK_SUFll_OCTHEX_TYPE(C##LL); \
|
||||
CHECK_SUFull_TYPE(C##ull); \
|
||||
CHECK_SUFull_TYPE(C##uLL); \
|
||||
CHECK_SUFull_TYPE(C##Ull); \
|
||||
CHECK_SUFull_TYPE(C##ULL);
|
||||
|
||||
#define CHECK_OCT_CONST(C) CHECK_OCTHEX_CONST(C)
|
||||
#define CHECK_HEX_CONST(C) \
|
||||
CHECK_OCTHEX_CONST(0x##C); \
|
||||
CHECK_OCTHEX_CONST(0X##C);
|
||||
|
||||
/* True iff "long long" is at least B bits. This presumes that (B-2)/3 is at
|
||||
most 63. */
|
||||
#define LLONG_AT_LEAST(B) \
|
||||
(LLONG_MAX >> ((B)-2)/3 >> ((B)-2)/3 \
|
||||
>> ((B)-2 - ((B)-2)/3 - ((B)-2)/3))
|
||||
|
||||
#define LLONG_HAS_BITS(B) (LLONG_AT_LEAST((B)) && !LLONG_AT_LEAST((B) + 1))
|
||||
|
||||
void
|
||||
foo (void)
|
||||
{
|
||||
/* Decimal. */
|
||||
/* Check all 2^n and 2^n - 1 up to 2^71 - 1. */
|
||||
CHECK_DEC_CONST(1);
|
||||
CHECK_DEC_CONST(2);
|
||||
CHECK_DEC_CONST(3);
|
||||
CHECK_DEC_CONST(4);
|
||||
CHECK_DEC_CONST(7);
|
||||
CHECK_DEC_CONST(8);
|
||||
CHECK_DEC_CONST(15);
|
||||
CHECK_DEC_CONST(16);
|
||||
CHECK_DEC_CONST(31);
|
||||
CHECK_DEC_CONST(32);
|
||||
CHECK_DEC_CONST(63);
|
||||
CHECK_DEC_CONST(64);
|
||||
CHECK_DEC_CONST(127);
|
||||
CHECK_DEC_CONST(128);
|
||||
CHECK_DEC_CONST(255);
|
||||
CHECK_DEC_CONST(256);
|
||||
CHECK_DEC_CONST(511);
|
||||
CHECK_DEC_CONST(512);
|
||||
CHECK_DEC_CONST(1023);
|
||||
CHECK_DEC_CONST(1024);
|
||||
CHECK_DEC_CONST(2047);
|
||||
CHECK_DEC_CONST(2048);
|
||||
CHECK_DEC_CONST(4095);
|
||||
CHECK_DEC_CONST(4096);
|
||||
CHECK_DEC_CONST(8191);
|
||||
CHECK_DEC_CONST(8192);
|
||||
CHECK_DEC_CONST(16383);
|
||||
CHECK_DEC_CONST(16384);
|
||||
CHECK_DEC_CONST(32767);
|
||||
CHECK_DEC_CONST(32768);
|
||||
CHECK_DEC_CONST(65535);
|
||||
CHECK_DEC_CONST(65536);
|
||||
CHECK_DEC_CONST(131071);
|
||||
CHECK_DEC_CONST(131072);
|
||||
CHECK_DEC_CONST(262143);
|
||||
CHECK_DEC_CONST(262144);
|
||||
CHECK_DEC_CONST(524287);
|
||||
CHECK_DEC_CONST(524288);
|
||||
CHECK_DEC_CONST(1048575);
|
||||
CHECK_DEC_CONST(1048576);
|
||||
CHECK_DEC_CONST(2097151);
|
||||
CHECK_DEC_CONST(2097152);
|
||||
CHECK_DEC_CONST(4194303);
|
||||
CHECK_DEC_CONST(4194304);
|
||||
CHECK_DEC_CONST(8388607);
|
||||
CHECK_DEC_CONST(8388608);
|
||||
CHECK_DEC_CONST(16777215);
|
||||
CHECK_DEC_CONST(16777216);
|
||||
CHECK_DEC_CONST(33554431);
|
||||
CHECK_DEC_CONST(33554432);
|
||||
CHECK_DEC_CONST(67108863);
|
||||
CHECK_DEC_CONST(67108864);
|
||||
CHECK_DEC_CONST(134217727);
|
||||
CHECK_DEC_CONST(134217728);
|
||||
CHECK_DEC_CONST(268435455);
|
||||
CHECK_DEC_CONST(268435456);
|
||||
CHECK_DEC_CONST(536870911);
|
||||
CHECK_DEC_CONST(536870912);
|
||||
CHECK_DEC_CONST(1073741823);
|
||||
CHECK_DEC_CONST(1073741824);
|
||||
CHECK_DEC_CONST(2147483647);
|
||||
CHECK_DEC_CONST(2147483648);
|
||||
CHECK_DEC_CONST(4294967295);
|
||||
CHECK_DEC_CONST(4294967296);
|
||||
CHECK_DEC_CONST(8589934591);
|
||||
CHECK_DEC_CONST(8589934592);
|
||||
CHECK_DEC_CONST(17179869183);
|
||||
CHECK_DEC_CONST(17179869184);
|
||||
CHECK_DEC_CONST(34359738367);
|
||||
CHECK_DEC_CONST(34359738368);
|
||||
CHECK_DEC_CONST(68719476735);
|
||||
CHECK_DEC_CONST(68719476736);
|
||||
CHECK_DEC_CONST(137438953471);
|
||||
CHECK_DEC_CONST(137438953472);
|
||||
CHECK_DEC_CONST(274877906943);
|
||||
CHECK_DEC_CONST(274877906944);
|
||||
CHECK_DEC_CONST(549755813887);
|
||||
CHECK_DEC_CONST(549755813888);
|
||||
CHECK_DEC_CONST(1099511627775);
|
||||
CHECK_DEC_CONST(1099511627776);
|
||||
CHECK_DEC_CONST(2199023255551);
|
||||
CHECK_DEC_CONST(2199023255552);
|
||||
CHECK_DEC_CONST(4398046511103);
|
||||
CHECK_DEC_CONST(4398046511104);
|
||||
CHECK_DEC_CONST(8796093022207);
|
||||
CHECK_DEC_CONST(8796093022208);
|
||||
CHECK_DEC_CONST(17592186044415);
|
||||
CHECK_DEC_CONST(17592186044416);
|
||||
CHECK_DEC_CONST(35184372088831);
|
||||
CHECK_DEC_CONST(35184372088832);
|
||||
CHECK_DEC_CONST(70368744177663);
|
||||
CHECK_DEC_CONST(70368744177664);
|
||||
CHECK_DEC_CONST(140737488355327);
|
||||
CHECK_DEC_CONST(140737488355328);
|
||||
CHECK_DEC_CONST(281474976710655);
|
||||
CHECK_DEC_CONST(281474976710656);
|
||||
CHECK_DEC_CONST(562949953421311);
|
||||
CHECK_DEC_CONST(562949953421312);
|
||||
CHECK_DEC_CONST(1125899906842623);
|
||||
CHECK_DEC_CONST(1125899906842624);
|
||||
CHECK_DEC_CONST(2251799813685247);
|
||||
CHECK_DEC_CONST(2251799813685248);
|
||||
CHECK_DEC_CONST(4503599627370495);
|
||||
CHECK_DEC_CONST(4503599627370496);
|
||||
CHECK_DEC_CONST(9007199254740991);
|
||||
CHECK_DEC_CONST(9007199254740992);
|
||||
CHECK_DEC_CONST(18014398509481983);
|
||||
CHECK_DEC_CONST(18014398509481984);
|
||||
CHECK_DEC_CONST(36028797018963967);
|
||||
CHECK_DEC_CONST(36028797018963968);
|
||||
CHECK_DEC_CONST(72057594037927935);
|
||||
CHECK_DEC_CONST(72057594037927936);
|
||||
CHECK_DEC_CONST(144115188075855871);
|
||||
CHECK_DEC_CONST(144115188075855872);
|
||||
CHECK_DEC_CONST(288230376151711743);
|
||||
CHECK_DEC_CONST(288230376151711744);
|
||||
CHECK_DEC_CONST(576460752303423487);
|
||||
CHECK_DEC_CONST(576460752303423488);
|
||||
CHECK_DEC_CONST(1152921504606846975);
|
||||
CHECK_DEC_CONST(1152921504606846976);
|
||||
CHECK_DEC_CONST(2305843009213693951);
|
||||
CHECK_DEC_CONST(2305843009213693952);
|
||||
CHECK_DEC_CONST(4611686018427387903);
|
||||
CHECK_DEC_CONST(4611686018427387904);
|
||||
CHECK_DEC_CONST(9223372036854775807);
|
||||
#if LLONG_AT_LEAST(65)
|
||||
CHECK_DEC_CONST(9223372036854775808);
|
||||
CHECK_DEC_CONST(18446744073709551615);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(66)
|
||||
CHECK_DEC_CONST(18446744073709551616);
|
||||
CHECK_DEC_CONST(36893488147419103231);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(67)
|
||||
CHECK_DEC_CONST(36893488147419103232);
|
||||
CHECK_DEC_CONST(73786976294838206463);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(68)
|
||||
CHECK_DEC_CONST(73786976294838206464);
|
||||
CHECK_DEC_CONST(147573952589676412927);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(69)
|
||||
CHECK_DEC_CONST(147573952589676412928);
|
||||
CHECK_DEC_CONST(295147905179352825855);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(70)
|
||||
CHECK_DEC_CONST(295147905179352825856);
|
||||
CHECK_DEC_CONST(590295810358705651711);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(71)
|
||||
CHECK_DEC_CONST(590295810358705651712);
|
||||
CHECK_DEC_CONST(1180591620717411303423);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(72)
|
||||
CHECK_DEC_CONST(1180591620717411303424);
|
||||
CHECK_DEC_CONST(2361183241434822606847);
|
||||
#endif
|
||||
/* Octal and hexadecimal. */
|
||||
/* Check all 2^n and 2^n - 1 up to 2^72 - 1. */
|
||||
CHECK_OCT_CONST(0);
|
||||
CHECK_HEX_CONST(0);
|
||||
CHECK_OCT_CONST(01);
|
||||
CHECK_HEX_CONST(1);
|
||||
CHECK_OCT_CONST(02);
|
||||
CHECK_HEX_CONST(2);
|
||||
CHECK_OCT_CONST(03);
|
||||
CHECK_HEX_CONST(3);
|
||||
CHECK_OCT_CONST(04);
|
||||
CHECK_HEX_CONST(4);
|
||||
CHECK_OCT_CONST(07);
|
||||
CHECK_HEX_CONST(7);
|
||||
CHECK_OCT_CONST(010);
|
||||
CHECK_HEX_CONST(8);
|
||||
CHECK_OCT_CONST(017);
|
||||
CHECK_HEX_CONST(f);
|
||||
CHECK_OCT_CONST(020);
|
||||
CHECK_HEX_CONST(10);
|
||||
CHECK_OCT_CONST(037);
|
||||
CHECK_HEX_CONST(1f);
|
||||
CHECK_OCT_CONST(040);
|
||||
CHECK_HEX_CONST(20);
|
||||
CHECK_OCT_CONST(077);
|
||||
CHECK_HEX_CONST(3f);
|
||||
CHECK_OCT_CONST(0100);
|
||||
CHECK_HEX_CONST(40);
|
||||
CHECK_OCT_CONST(0177);
|
||||
CHECK_HEX_CONST(7f);
|
||||
CHECK_OCT_CONST(0200);
|
||||
CHECK_HEX_CONST(80);
|
||||
CHECK_OCT_CONST(0377);
|
||||
CHECK_HEX_CONST(ff);
|
||||
CHECK_OCT_CONST(0400);
|
||||
CHECK_HEX_CONST(100);
|
||||
CHECK_OCT_CONST(0777);
|
||||
CHECK_HEX_CONST(1ff);
|
||||
CHECK_OCT_CONST(01000);
|
||||
CHECK_HEX_CONST(200);
|
||||
CHECK_OCT_CONST(01777);
|
||||
CHECK_HEX_CONST(3ff);
|
||||
CHECK_OCT_CONST(02000);
|
||||
CHECK_HEX_CONST(400);
|
||||
CHECK_OCT_CONST(03777);
|
||||
CHECK_HEX_CONST(7ff);
|
||||
CHECK_OCT_CONST(04000);
|
||||
CHECK_HEX_CONST(800);
|
||||
CHECK_OCT_CONST(07777);
|
||||
CHECK_HEX_CONST(fff);
|
||||
CHECK_OCT_CONST(010000);
|
||||
CHECK_HEX_CONST(1000);
|
||||
CHECK_OCT_CONST(017777);
|
||||
CHECK_HEX_CONST(1fff);
|
||||
CHECK_OCT_CONST(020000);
|
||||
CHECK_HEX_CONST(2000);
|
||||
CHECK_OCT_CONST(037777);
|
||||
CHECK_HEX_CONST(3fff);
|
||||
CHECK_OCT_CONST(040000);
|
||||
CHECK_HEX_CONST(4000);
|
||||
CHECK_OCT_CONST(077777);
|
||||
CHECK_HEX_CONST(7fff);
|
||||
CHECK_OCT_CONST(0100000);
|
||||
CHECK_HEX_CONST(8000);
|
||||
CHECK_OCT_CONST(0177777);
|
||||
CHECK_HEX_CONST(ffff);
|
||||
CHECK_OCT_CONST(0200000);
|
||||
CHECK_HEX_CONST(10000);
|
||||
CHECK_OCT_CONST(0377777);
|
||||
CHECK_HEX_CONST(1ffff);
|
||||
CHECK_OCT_CONST(0400000);
|
||||
CHECK_HEX_CONST(20000);
|
||||
CHECK_OCT_CONST(0777777);
|
||||
CHECK_HEX_CONST(3ffff);
|
||||
CHECK_OCT_CONST(01000000);
|
||||
CHECK_HEX_CONST(40000);
|
||||
CHECK_OCT_CONST(01777777);
|
||||
CHECK_HEX_CONST(7ffff);
|
||||
CHECK_OCT_CONST(02000000);
|
||||
CHECK_HEX_CONST(80000);
|
||||
CHECK_OCT_CONST(03777777);
|
||||
CHECK_HEX_CONST(fffff);
|
||||
CHECK_OCT_CONST(04000000);
|
||||
CHECK_HEX_CONST(100000);
|
||||
CHECK_OCT_CONST(07777777);
|
||||
CHECK_HEX_CONST(1fffff);
|
||||
CHECK_OCT_CONST(010000000);
|
||||
CHECK_HEX_CONST(200000);
|
||||
CHECK_OCT_CONST(017777777);
|
||||
CHECK_HEX_CONST(3fffff);
|
||||
CHECK_OCT_CONST(020000000);
|
||||
CHECK_HEX_CONST(400000);
|
||||
CHECK_OCT_CONST(037777777);
|
||||
CHECK_HEX_CONST(7fffff);
|
||||
CHECK_OCT_CONST(040000000);
|
||||
CHECK_HEX_CONST(800000);
|
||||
CHECK_OCT_CONST(077777777);
|
||||
CHECK_HEX_CONST(ffffff);
|
||||
CHECK_OCT_CONST(0100000000);
|
||||
CHECK_HEX_CONST(1000000);
|
||||
CHECK_OCT_CONST(0177777777);
|
||||
CHECK_HEX_CONST(1ffffff);
|
||||
CHECK_OCT_CONST(0200000000);
|
||||
CHECK_HEX_CONST(2000000);
|
||||
CHECK_OCT_CONST(0377777777);
|
||||
CHECK_HEX_CONST(3ffffff);
|
||||
CHECK_OCT_CONST(0400000000);
|
||||
CHECK_HEX_CONST(4000000);
|
||||
CHECK_OCT_CONST(0777777777);
|
||||
CHECK_HEX_CONST(7ffffff);
|
||||
CHECK_OCT_CONST(01000000000);
|
||||
CHECK_HEX_CONST(8000000);
|
||||
CHECK_OCT_CONST(01777777777);
|
||||
CHECK_HEX_CONST(fffffff);
|
||||
CHECK_OCT_CONST(02000000000);
|
||||
CHECK_HEX_CONST(10000000);
|
||||
CHECK_OCT_CONST(03777777777);
|
||||
CHECK_HEX_CONST(1fffffff);
|
||||
CHECK_OCT_CONST(04000000000);
|
||||
CHECK_HEX_CONST(20000000);
|
||||
CHECK_OCT_CONST(07777777777);
|
||||
CHECK_HEX_CONST(3fffffff);
|
||||
CHECK_OCT_CONST(010000000000);
|
||||
CHECK_HEX_CONST(40000000);
|
||||
CHECK_OCT_CONST(017777777777);
|
||||
CHECK_HEX_CONST(7fffffff);
|
||||
CHECK_OCT_CONST(020000000000);
|
||||
CHECK_HEX_CONST(80000000);
|
||||
CHECK_OCT_CONST(037777777777);
|
||||
CHECK_HEX_CONST(ffffffff);
|
||||
CHECK_OCT_CONST(040000000000);
|
||||
CHECK_HEX_CONST(100000000);
|
||||
CHECK_OCT_CONST(077777777777);
|
||||
CHECK_HEX_CONST(1ffffffff);
|
||||
CHECK_OCT_CONST(0100000000000);
|
||||
CHECK_HEX_CONST(200000000);
|
||||
CHECK_OCT_CONST(0177777777777);
|
||||
CHECK_HEX_CONST(3ffffffff);
|
||||
CHECK_OCT_CONST(0200000000000);
|
||||
CHECK_HEX_CONST(400000000);
|
||||
CHECK_OCT_CONST(0377777777777);
|
||||
CHECK_HEX_CONST(7ffffffff);
|
||||
CHECK_OCT_CONST(0400000000000);
|
||||
CHECK_HEX_CONST(800000000);
|
||||
CHECK_OCT_CONST(0777777777777);
|
||||
CHECK_HEX_CONST(fffffffff);
|
||||
CHECK_OCT_CONST(01000000000000);
|
||||
CHECK_HEX_CONST(1000000000);
|
||||
CHECK_OCT_CONST(01777777777777);
|
||||
CHECK_HEX_CONST(1fffffffff);
|
||||
CHECK_OCT_CONST(02000000000000);
|
||||
CHECK_HEX_CONST(2000000000);
|
||||
CHECK_OCT_CONST(03777777777777);
|
||||
CHECK_HEX_CONST(3fffffffff);
|
||||
CHECK_OCT_CONST(04000000000000);
|
||||
CHECK_HEX_CONST(4000000000);
|
||||
CHECK_OCT_CONST(07777777777777);
|
||||
CHECK_HEX_CONST(7fffffffff);
|
||||
CHECK_OCT_CONST(010000000000000);
|
||||
CHECK_HEX_CONST(8000000000);
|
||||
CHECK_OCT_CONST(017777777777777);
|
||||
CHECK_HEX_CONST(ffffffffff);
|
||||
CHECK_OCT_CONST(020000000000000);
|
||||
CHECK_HEX_CONST(10000000000);
|
||||
CHECK_OCT_CONST(037777777777777);
|
||||
CHECK_HEX_CONST(1ffffffffff);
|
||||
CHECK_OCT_CONST(040000000000000);
|
||||
CHECK_HEX_CONST(20000000000);
|
||||
CHECK_OCT_CONST(077777777777777);
|
||||
CHECK_HEX_CONST(3ffffffffff);
|
||||
CHECK_OCT_CONST(0100000000000000);
|
||||
CHECK_HEX_CONST(40000000000);
|
||||
CHECK_OCT_CONST(0177777777777777);
|
||||
CHECK_HEX_CONST(7ffffffffff);
|
||||
CHECK_OCT_CONST(0200000000000000);
|
||||
CHECK_HEX_CONST(80000000000);
|
||||
CHECK_OCT_CONST(0377777777777777);
|
||||
CHECK_HEX_CONST(fffffffffff);
|
||||
CHECK_OCT_CONST(0400000000000000);
|
||||
CHECK_HEX_CONST(100000000000);
|
||||
CHECK_OCT_CONST(0777777777777777);
|
||||
CHECK_HEX_CONST(1fffffffffff);
|
||||
CHECK_OCT_CONST(01000000000000000);
|
||||
CHECK_HEX_CONST(200000000000);
|
||||
CHECK_OCT_CONST(01777777777777777);
|
||||
CHECK_HEX_CONST(3fffffffffff);
|
||||
CHECK_OCT_CONST(02000000000000000);
|
||||
CHECK_HEX_CONST(400000000000);
|
||||
CHECK_OCT_CONST(03777777777777777);
|
||||
CHECK_HEX_CONST(7fffffffffff);
|
||||
CHECK_OCT_CONST(04000000000000000);
|
||||
CHECK_HEX_CONST(800000000000);
|
||||
CHECK_OCT_CONST(07777777777777777);
|
||||
CHECK_HEX_CONST(ffffffffffff);
|
||||
CHECK_OCT_CONST(010000000000000000);
|
||||
CHECK_HEX_CONST(1000000000000);
|
||||
CHECK_OCT_CONST(017777777777777777);
|
||||
CHECK_HEX_CONST(1ffffffffffff);
|
||||
CHECK_OCT_CONST(020000000000000000);
|
||||
CHECK_HEX_CONST(2000000000000);
|
||||
CHECK_OCT_CONST(037777777777777777);
|
||||
CHECK_HEX_CONST(3ffffffffffff);
|
||||
CHECK_OCT_CONST(040000000000000000);
|
||||
CHECK_HEX_CONST(4000000000000);
|
||||
CHECK_OCT_CONST(077777777777777777);
|
||||
CHECK_HEX_CONST(7ffffffffffff);
|
||||
CHECK_OCT_CONST(0100000000000000000);
|
||||
CHECK_HEX_CONST(8000000000000);
|
||||
CHECK_OCT_CONST(0177777777777777777);
|
||||
CHECK_HEX_CONST(fffffffffffff);
|
||||
CHECK_OCT_CONST(0200000000000000000);
|
||||
CHECK_HEX_CONST(10000000000000);
|
||||
CHECK_OCT_CONST(0377777777777777777);
|
||||
CHECK_HEX_CONST(1fffffffffffff);
|
||||
CHECK_OCT_CONST(0400000000000000000);
|
||||
CHECK_HEX_CONST(20000000000000);
|
||||
CHECK_OCT_CONST(0777777777777777777);
|
||||
CHECK_HEX_CONST(3fffffffffffff);
|
||||
CHECK_OCT_CONST(01000000000000000000);
|
||||
CHECK_HEX_CONST(40000000000000);
|
||||
CHECK_OCT_CONST(01777777777777777777);
|
||||
CHECK_HEX_CONST(7fffffffffffff);
|
||||
CHECK_OCT_CONST(02000000000000000000);
|
||||
CHECK_HEX_CONST(80000000000000);
|
||||
CHECK_OCT_CONST(03777777777777777777);
|
||||
CHECK_HEX_CONST(ffffffffffffff);
|
||||
CHECK_OCT_CONST(04000000000000000000);
|
||||
CHECK_HEX_CONST(100000000000000);
|
||||
CHECK_OCT_CONST(07777777777777777777);
|
||||
CHECK_HEX_CONST(1ffffffffffffff);
|
||||
CHECK_OCT_CONST(010000000000000000000);
|
||||
CHECK_HEX_CONST(200000000000000);
|
||||
CHECK_OCT_CONST(017777777777777777777);
|
||||
CHECK_HEX_CONST(3ffffffffffffff);
|
||||
CHECK_OCT_CONST(020000000000000000000);
|
||||
CHECK_HEX_CONST(400000000000000);
|
||||
CHECK_OCT_CONST(037777777777777777777);
|
||||
CHECK_HEX_CONST(7ffffffffffffff);
|
||||
CHECK_OCT_CONST(040000000000000000000);
|
||||
CHECK_HEX_CONST(800000000000000);
|
||||
CHECK_OCT_CONST(077777777777777777777);
|
||||
CHECK_HEX_CONST(fffffffffffffff);
|
||||
CHECK_OCT_CONST(0100000000000000000000);
|
||||
CHECK_HEX_CONST(1000000000000000);
|
||||
CHECK_OCT_CONST(0177777777777777777777);
|
||||
CHECK_HEX_CONST(1fffffffffffffff);
|
||||
CHECK_OCT_CONST(0200000000000000000000);
|
||||
CHECK_HEX_CONST(2000000000000000);
|
||||
CHECK_OCT_CONST(0377777777777777777777);
|
||||
CHECK_HEX_CONST(3fffffffffffffff);
|
||||
CHECK_OCT_CONST(0400000000000000000000);
|
||||
CHECK_HEX_CONST(4000000000000000);
|
||||
CHECK_OCT_CONST(0777777777777777777777);
|
||||
CHECK_HEX_CONST(7fffffffffffffff);
|
||||
CHECK_OCT_CONST(01000000000000000000000);
|
||||
CHECK_HEX_CONST(8000000000000000);
|
||||
CHECK_OCT_CONST(01777777777777777777777);
|
||||
CHECK_HEX_CONST(ffffffffffffffff);
|
||||
#if LLONG_AT_LEAST(65)
|
||||
CHECK_OCT_CONST(02000000000000000000000);
|
||||
CHECK_HEX_CONST(10000000000000000);
|
||||
CHECK_OCT_CONST(03777777777777777777777);
|
||||
CHECK_HEX_CONST(1ffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(66)
|
||||
CHECK_OCT_CONST(04000000000000000000000);
|
||||
CHECK_HEX_CONST(20000000000000000);
|
||||
CHECK_OCT_CONST(07777777777777777777777);
|
||||
CHECK_HEX_CONST(3ffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(67)
|
||||
CHECK_OCT_CONST(010000000000000000000000);
|
||||
CHECK_HEX_CONST(40000000000000000);
|
||||
CHECK_OCT_CONST(017777777777777777777777);
|
||||
CHECK_HEX_CONST(7ffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(68)
|
||||
CHECK_OCT_CONST(020000000000000000000000);
|
||||
CHECK_HEX_CONST(80000000000000000);
|
||||
CHECK_OCT_CONST(037777777777777777777777);
|
||||
CHECK_HEX_CONST(fffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(69)
|
||||
CHECK_OCT_CONST(040000000000000000000000);
|
||||
CHECK_HEX_CONST(100000000000000000);
|
||||
CHECK_OCT_CONST(077777777777777777777777);
|
||||
CHECK_HEX_CONST(1fffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(70)
|
||||
CHECK_OCT_CONST(0100000000000000000000000);
|
||||
CHECK_HEX_CONST(200000000000000000);
|
||||
CHECK_OCT_CONST(0177777777777777777777777);
|
||||
CHECK_HEX_CONST(3fffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(71)
|
||||
CHECK_OCT_CONST(0200000000000000000000000);
|
||||
CHECK_HEX_CONST(400000000000000000);
|
||||
CHECK_OCT_CONST(0377777777777777777777777);
|
||||
CHECK_HEX_CONST(7fffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(72)
|
||||
CHECK_OCT_CONST(0400000000000000000000000);
|
||||
CHECK_HEX_CONST(800000000000000000);
|
||||
CHECK_OCT_CONST(0777777777777777777777777);
|
||||
CHECK_HEX_CONST(ffffffffffffffffff);
|
||||
#endif
|
||||
}
|
4
INPUTS/carbon_h.c
Normal file
4
INPUTS/carbon_h.c
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
//#import<vecLib/vecLib.h>
|
5
INPUTS/iostream.cc
Normal file
5
INPUTS/iostream.cc
Normal file
@ -0,0 +1,5 @@
|
||||
// clang -I/usr/include/c++/4.0.0 -I/usr/include/c++/4.0.0/powerpc-apple-darwin8 -I/usr/include/c++/4.0.0/backward INPUTS/iostream.cc -Eonly
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <stdint.h>
|
17
INPUTS/macro_pounder_fn.c
Normal file
17
INPUTS/macro_pounder_fn.c
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
// This pounds on macro expansion for performance reasons. This is currently
|
||||
// heavily constrained by darwin's malloc.
|
||||
|
||||
// Function-like macros.
|
||||
#define A0(A, B) A B
|
||||
#define A1(A, B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B)
|
||||
#define A2(A, B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B)
|
||||
#define A3(A, B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B)
|
||||
#define A4(A, B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B)
|
||||
#define A5(A, B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B)
|
||||
#define A6(A, B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B)
|
||||
#define A7(A, B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B)
|
||||
#define A8(A, B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B)
|
||||
|
||||
A8(a, b)
|
||||
|
16
INPUTS/macro_pounder_obj.c
Normal file
16
INPUTS/macro_pounder_obj.c
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
// This pounds on macro expansion for performance reasons. This is currently
|
||||
// heavily constrained by darwin's malloc.
|
||||
|
||||
// Object-like expansions
|
||||
#define A0 a b
|
||||
#define A1 A0 A0 A0 A0 A0 A0
|
||||
#define A2 A1 A1 A1 A1 A1 A1
|
||||
#define A3 A2 A2 A2 A2 A2 A2
|
||||
#define A4 A3 A3 A3 A3 A3 A3
|
||||
#define A5 A4 A4 A4 A4 A4 A4
|
||||
#define A6 A5 A5 A5 A5 A5 A5
|
||||
#define A7 A6 A6 A6 A6 A6 A6
|
||||
#define A8 A7 A7 A7 A7 A7 A7
|
||||
|
||||
A8
|
47
INPUTS/stpcpy-test.c
Normal file
47
INPUTS/stpcpy-test.c
Normal file
@ -0,0 +1,47 @@
|
||||
#define __extension__
|
||||
|
||||
#define __stpcpy(dest, src) (__extension__ (__builtin_constant_p (src) ? (__string2_1bptr_p (src) && strlen (src) + 1 <= 8 ? __stpcpy_small (dest, __stpcpy_args (src), strlen (src) + 1) : ((char *) __mempcpy (dest, src, strlen (src) + 1) - 1)) : __stpcpy (dest, src)))
|
||||
#define stpcpy(dest, src) __stpcpy (dest, src)
|
||||
#define __stpcpy_args(src) __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
|
||||
|
||||
#define __mempcpy(dest, src, n) (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n) && __string2_1bptr_p (src) && n <= 8 ? __mempcpy_small (dest, __mempcpy_args (src), n) : __mempcpy (dest, src, n)))
|
||||
#define mempcpy(dest, src, n) __mempcpy (dest, src, n)
|
||||
#define __mempcpy_args(src) ((char *) (src))[0], ((char *) (src))[2], ((char *) (src))[4], ((char *) (src))[6], __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
|
||||
|
||||
#define __STRING2_SMALL_GET16(src, idx) (((__const unsigned char *) (__const char *) (src))[idx + 1] << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
|
||||
|
||||
#define __STRING2_SMALL_GET32(src, idx) (((((__const unsigned char *) (__const char *) (src))[idx + 3] << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 2]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 1]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
|
||||
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
63
LICENSE.TXT
Normal file
63
LICENSE.TXT
Normal file
@ -0,0 +1,63 @@
|
||||
==============================================================================
|
||||
LLVM Release License
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
The LLVM software contains code written by third parties. Such software will
|
||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
||||
This file will describe the copyrights, license, and restrictions which apply
|
||||
to that code.
|
||||
|
||||
The disclaimer of warranty in the University of Illinois Open Source License
|
||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
||||
other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
<none yet>
|
||||
|
32
Makefile
Normal file
32
Makefile
Normal file
@ -0,0 +1,32 @@
|
||||
LEVEL = ../..
|
||||
DIRS := include lib tools docs
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
test::
|
||||
$(Verb) if [ ! -f test/Makefile ]; then \
|
||||
$(MKDIR) test; \
|
||||
$(CP) $(PROJ_SRC_DIR)/test/Makefile test/Makefile; \
|
||||
fi
|
||||
endif
|
||||
|
||||
test::
|
||||
@ $(MAKE) -C test
|
||||
|
||||
report::
|
||||
@ $(MAKE) -C test report
|
||||
|
||||
clean::
|
||||
@ $(MAKE) -C test clean
|
||||
|
||||
tags::
|
||||
$(Verb) etags `find . -type f -name \*.h | grep -v /lib/Headers | grep -v /test/` `find . -type f -name \*.cpp | grep -v /lib/Headers | grep -v /test/`
|
||||
|
||||
cscope.files:
|
||||
find tools lib include -name '*.cpp' \
|
||||
-or -name '*.def' \
|
||||
-or -name '*.td' \
|
||||
-or -name '*.h' > cscope.files
|
||||
|
||||
.PHONY: test report clean cscope.files
|
5
ModuleInfo.txt
Normal file
5
ModuleInfo.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# This file provides information for llvm-top
|
||||
DepModule: llvm
|
||||
ConfigCmd:
|
||||
ConfigTest:
|
||||
BuildCmd:
|
86
NOTES.txt
Normal file
86
NOTES.txt
Normal file
@ -0,0 +1,86 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Random Notes
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C90/C99/C++ Comparisons:
|
||||
http://david.tribble.com/text/cdiffs.htm
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
To time GCC preprocessing speed without output, use:
|
||||
"time gcc -MM file"
|
||||
This is similar to -Eonly.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Creating and using a PTH file for performance measurement (use a release-asserts
|
||||
build).
|
||||
|
||||
$ clang -x objective-c-header INPUTS/Cocoa_h.m -o /tmp/tokencache
|
||||
$ clang -token-cache /tmp/tokencache INPUTS/Cocoa_h.m
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C++ Template Instantiation benchmark:
|
||||
http://users.rcn.com/abrahams/instantiation_speed/index.html
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
TODO: File Manager Speedup:
|
||||
|
||||
We currently do a lot of stat'ing for files that don't exist, particularly
|
||||
when lots of -I paths exist (e.g. see the <iostream> example, check for
|
||||
failures in stat in FileManager::getFile). It would be far better to make
|
||||
the following changes:
|
||||
1. FileEntry contains a sys::Path instead of a std::string for Name.
|
||||
2. sys::Path contains timestamp and size, lazily computed. Eliminate from
|
||||
FileEntry.
|
||||
3. File UIDs are created on request, not when files are opened.
|
||||
These changes make it possible to efficiently have FileEntry objects for
|
||||
files that exist on the file system, but have not been used yet.
|
||||
|
||||
Once this is done:
|
||||
1. DirectoryEntry gets a boolean value "has read entries". When false, not
|
||||
all entries in the directory are in the file mgr, when true, they are.
|
||||
2. Instead of stat'ing the file in FileManager::getFile, check to see if
|
||||
the dir has been read. If so, fail immediately, if not, read the dir,
|
||||
then retry.
|
||||
3. Reading the dir uses the getdirentries syscall, creating an FileEntry
|
||||
for all files found.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Specifying targets: -triple and -arch
|
||||
===---------------------------------------------------------------------===//
|
||||
|
||||
The clang supports "-triple" and "-arch" options. At most one -triple and one
|
||||
-arch option may be specified. Both are optional.
|
||||
|
||||
The "selection of target" behavior is defined as follows:
|
||||
|
||||
(1) If the user does not specify -triple, we default to the host triple.
|
||||
(2) If the user specifies a -arch, that overrides the arch in the host or
|
||||
specified triple.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
|
||||
verifyInputConstraint and verifyOutputConstraint should not return bool.
|
||||
|
||||
Instead we should return something like:
|
||||
|
||||
enum VerifyConstraintResult {
|
||||
Valid,
|
||||
|
||||
// Output only
|
||||
OutputOperandConstraintLacksEqualsCharacter,
|
||||
MatchingConstraintNotValidInOutputOperand,
|
||||
|
||||
// Input only
|
||||
InputOperandConstraintContainsEqualsCharacter,
|
||||
MatchingConstraintReferencesInvalidOperandNumber,
|
||||
|
||||
// Both
|
||||
PercentConstraintUsedWithLastOperand
|
||||
};
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
178
README.txt
Normal file
178
README.txt
Normal file
@ -0,0 +1,178 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C Language Family Front-end
|
||||
//===----------------------------------------------------------------------===//
|
||||
Chris Lattner
|
||||
|
||||
I. Introduction:
|
||||
|
||||
clang: noun
|
||||
1. A loud, resonant, metallic sound.
|
||||
2. The strident call of a crane or goose.
|
||||
3. C-language family front-end toolkit.
|
||||
|
||||
The world needs better compiler tools, tools which are built as libraries. This
|
||||
design point allows reuse of the tools in new and novel ways. However, building
|
||||
the tools as libraries isn't enough: they must have clean APIs, be as
|
||||
decoupled from each other as possible, and be easy to modify/extend. This
|
||||
requires clean layering, decent design, and avoiding tying the libraries to a
|
||||
specific use. Oh yeah, did I mention that we want the resultant libraries to
|
||||
be as fast as possible? :)
|
||||
|
||||
This front-end is built as a component of the LLVM toolkit that can be used
|
||||
with the LLVM backend or independently of it. In this spirit, the API has been
|
||||
carefully designed as the following components:
|
||||
|
||||
libsupport - Basic support library, reused from LLVM.
|
||||
|
||||
libsystem - System abstraction library, reused from LLVM.
|
||||
|
||||
libbasic - Diagnostics, SourceLocations, SourceBuffer abstraction,
|
||||
file system caching for input source files. This depends on
|
||||
libsupport and libsystem.
|
||||
|
||||
libast - Provides classes to represent the C AST, the C type system,
|
||||
builtin functions, and various helpers for analyzing and
|
||||
manipulating the AST (visitors, pretty printers, etc). This
|
||||
library depends on libbasic.
|
||||
|
||||
|
||||
liblex - C/C++/ObjC lexing and preprocessing, identifier hash table,
|
||||
pragma handling, tokens, and macros. This depends on libbasic.
|
||||
|
||||
libparse - C (for now) parsing and local semantic analysis. This library
|
||||
invokes coarse-grained 'Actions' provided by the client to do
|
||||
stuff (e.g. libsema builds ASTs). This depends on liblex.
|
||||
|
||||
libsema - Provides a set of parser actions to build a standardized AST
|
||||
for programs. AST's are 'streamed' out a top-level declaration
|
||||
at a time, allowing clients to use decl-at-a-time processing,
|
||||
build up entire translation units, or even build 'whole
|
||||
program' ASTs depending on how they use the APIs. This depends
|
||||
on libast and libparse.
|
||||
|
||||
librewrite - Fast, scalable rewriting of source code. This operates on
|
||||
the raw syntactic text of source code, allowing a client
|
||||
to insert and delete text in very large source files using
|
||||
the same source location information embedded in ASTs. This
|
||||
is intended to be a low-level API that is useful for
|
||||
higher-level clients and libraries such as code refactoring.
|
||||
|
||||
libanalysis - Source-level dataflow analysis useful for performing analyses
|
||||
such as computing live variables. It also includes a
|
||||
path-sensitive "graph-reachability" engine for writing
|
||||
analyses that reason about different possible paths of
|
||||
execution through source code. This is currently being
|
||||
employed to write a set of checks for finding bugs in software.
|
||||
|
||||
libcodegen - Lower the AST to LLVM IR for optimization & codegen. Depends
|
||||
on libast.
|
||||
|
||||
clang - An example driver, client of the libraries at various levels.
|
||||
This depends on all these libraries, and on LLVM VMCore.
|
||||
|
||||
This front-end has been intentionally built as a DAG of libraries, making it
|
||||
easy to reuse individual parts or replace pieces if desired. For example, to
|
||||
build a preprocessor, you take the Basic and Lexer libraries. If you want an
|
||||
indexer, you take those plus the Parser library and provide some actions for
|
||||
indexing. If you want a refactoring, static analysis, or source-to-source
|
||||
compiler tool, it makes sense to take those plus the AST building and semantic
|
||||
analyzer library. Finally, if you want to use this with the LLVM backend,
|
||||
you'd take these components plus the AST to LLVM lowering code.
|
||||
|
||||
In the future I hope this toolkit will grow to include new and interesting
|
||||
components, including a C++ front-end, ObjC support, and a whole lot of other
|
||||
things.
|
||||
|
||||
Finally, it should be pointed out that the goal here is to build something that
|
||||
is high-quality and industrial-strength: all the obnoxious features of the C
|
||||
family must be correctly supported (trigraphs, preprocessor arcana, K&R-style
|
||||
prototypes, GCC/MS extensions, etc). It cannot be used if it is not 'real'.
|
||||
|
||||
|
||||
II. Usage of clang driver:
|
||||
|
||||
* Basic Command-Line Options:
|
||||
- Help: clang --help
|
||||
- Standard GCC options accepted: -E, -I*, -i*, -pedantic, -std=c90, etc.
|
||||
- To make diagnostics more gcc-like: -fno-caret-diagnostics -fno-show-column
|
||||
- Enable metric printing: -stats
|
||||
|
||||
* -fsyntax-only is currently the default mode.
|
||||
|
||||
* -E mode works the same way as GCC.
|
||||
|
||||
* -Eonly mode does all preprocessing, but does not print the output,
|
||||
useful for timing the preprocessor.
|
||||
|
||||
* -fsyntax-only is currently partially implemented, lacking some
|
||||
semantic analysis (some errors and warnings are not produced).
|
||||
|
||||
* -parse-noop parses code without building an AST. This is useful
|
||||
for timing the cost of the parser without including AST building
|
||||
time.
|
||||
|
||||
* -parse-ast builds ASTs, but doesn't print them. This is most
|
||||
useful for timing AST building vs -parse-noop.
|
||||
|
||||
* -parse-ast-print pretty prints most expression and statements nodes.
|
||||
|
||||
* -parse-ast-check checks that diagnostic messages that are expected
|
||||
are reported and that those which are reported are expected.
|
||||
|
||||
* -dump-cfg builds ASTs and then CFGs. CFGs are then pretty-printed.
|
||||
|
||||
* -view-cfg builds ASTs and then CFGs. CFGs are then visualized by
|
||||
invoking Graphviz.
|
||||
|
||||
For more information on getting Graphviz to work with clang/LLVM,
|
||||
see: http://llvm.org/docs/ProgrammersManual.html#ViewGraph
|
||||
|
||||
|
||||
III. Current advantages over GCC:
|
||||
|
||||
* Column numbers are fully tracked (no 256 col limit, no GCC-style pruning).
|
||||
* All diagnostics have column numbers, includes 'caret diagnostics', and they
|
||||
highlight regions of interesting code (e.g. the LHS and RHS of a binop).
|
||||
* Full diagnostic customization by client (can format diagnostics however they
|
||||
like, e.g. in an IDE or refactoring tool) through DiagnosticClient interface.
|
||||
* Built as a framework, can be reused by multiple tools.
|
||||
* All languages supported linked into same library (no cc1,cc1obj, ...).
|
||||
* mmap's code in read-only, does not dirty the pages like GCC (mem footprint).
|
||||
* LLVM License, can be linked into non-GPL projects.
|
||||
* Full diagnostic control, per diagnostic. Diagnostics are identified by ID.
|
||||
* Significantly faster than GCC at semantic analysis, parsing, preprocessing
|
||||
and lexing.
|
||||
* Defers exposing platform-specific stuff to as late as possible, tracks use of
|
||||
platform-specific features (e.g. #ifdef PPC) to allow 'portable bytecodes'.
|
||||
* The lexer doesn't rely on the "lexer hack": it has no notion of scope and
|
||||
does not categorize identifiers as types or variables -- this is up to the
|
||||
parser to decide.
|
||||
|
||||
Potential Future Features:
|
||||
|
||||
* Fine grained diag control within the source (#pragma enable/disable warning).
|
||||
* Better token tracking within macros? (Token came from this line, which is
|
||||
a macro argument instantiated here, recursively instantiated here).
|
||||
* Fast #import with a module system.
|
||||
* Dependency tracking: change to header file doesn't recompile every function
|
||||
that texually depends on it: recompile only those functions that need it.
|
||||
This is aka 'incremental parsing'.
|
||||
|
||||
|
||||
IV. Missing Functionality / Improvements
|
||||
|
||||
Lexer:
|
||||
* Source character mapping. GCC supports ASCII and UTF-8.
|
||||
See GCC options: -ftarget-charset and -ftarget-wide-charset.
|
||||
* Universal character support. Experimental in GCC, enabled with
|
||||
-fextended-identifiers.
|
||||
* -fpreprocessed mode.
|
||||
|
||||
Preprocessor:
|
||||
* #assert/#unassert
|
||||
* MSExtension: "L#param" stringizes to a wide string literal.
|
||||
* Add support for -M*
|
||||
|
||||
Traditional Preprocessor:
|
||||
* Currently, we have none. :)
|
||||
|
68
TODO.txt
Normal file
68
TODO.txt
Normal file
@ -0,0 +1,68 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// 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 ||.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Lexer-related diagnostics should point to the problematic character, not the
|
||||
start of the token. For example:
|
||||
|
||||
int y = 0000\
|
||||
00080;
|
||||
|
||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
||||
int y = 0000\
|
||||
^
|
||||
|
||||
should be:
|
||||
|
||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
||||
00080;
|
||||
^
|
||||
|
||||
This specific diagnostic is implemented, but others should be updated.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C++ (checker): For iterators, warn of the use of "iterator++" instead
|
||||
of "++iterator" when when the value returned by operator++(int) is
|
||||
ignored.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
We want to keep more source range information in Declarator to help
|
||||
produce better diagnostics. Declarator::getSourceRange() should be
|
||||
implemented to give a range for the whole declarator with all of its
|
||||
specifiers, and DeclaratorChunk::ParamInfo should also have a source
|
||||
range covering the whole parameter, so that an error message like this:
|
||||
|
||||
overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
|
||||
X operator++(X&, const float& f);
|
||||
^
|
||||
can be turned into something like this:
|
||||
|
||||
overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
|
||||
X operator++(X&, const float& f);
|
||||
^ ~~~~~~~~~~~~~~
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
For terminal output, we should consider limiting the amount of
|
||||
diagnostic text we print once the first error has been
|
||||
encountered. For example, once we have produced an error diagnostic,
|
||||
we should only continue producing diagnostics until we have produced a
|
||||
page full of results (say, 50 lines of text). Beyond that, (1) the
|
||||
remaining errors are likely to be less interesting, and (2) the poor
|
||||
user has to scroll his terminal to find out where things went wrong.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
More ideas for code modification hints:
|
||||
- If no member of a given name is found in a class/struct, search through the names of entities that do exist in the class and suggest the closest candidate. e.g., if I write "DS.setTypeSpecType", it would suggest "DS.SetTypeSpecType" (edit distance = 1).
|
||||
- If a class member is defined out-of-line but isn't in the class declaration (and there are no close matches!), provide the option to add an in-class declaration.
|
||||
- Fix-it hints for the inclusion of headers when needed for particular features (e.g., <typeinfo> for typeid)
|
||||
- Change "foo.bar" to "foo->bar" when "foo" is a pointer.
|
1836
clang.xcodeproj/project.pbxproj
Normal file
1836
clang.xcodeproj/project.pbxproj
Normal file
File diff suppressed because it is too large
Load Diff
258
docs/AnalyzerRegions.html
Normal file
258
docs/AnalyzerRegions.html
Normal file
@ -0,0 +1,258 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Static Analyzer Design Document: Memory Regions</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Static Analyzer Design Document: Memory Regions</h1>
|
||||
|
||||
<h3>Authors</h3>
|
||||
|
||||
<p>Ted Kremenek, <tt>kremenek at apple</tt><br>
|
||||
Zhongxing Xu, <tt>xuzhongzhing at gmail</tt></p>
|
||||
|
||||
<h2 id="intro">Introduction</h2>
|
||||
|
||||
<p>The path-sensitive analysis engine in libAnalysis employs an extensible API
|
||||
for abstractly modeling the memory of an analyzed program. This API employs the
|
||||
concept of "memory regions" to abstractly model chunks of program memory such as
|
||||
program variables and dynamically allocated memory such as those returned from
|
||||
'malloc' and 'alloca'. Regions are hierarchical, with subregions modeling
|
||||
subtyping relationships, field and array offsets into larger chunks of memory,
|
||||
and so on.</p>
|
||||
|
||||
<p>The region API consists of two components:</p>
|
||||
|
||||
<ul> <li>A taxonomy and representation of regions themselves within the analyzer
|
||||
engine. The primary definitions and interfaces are described in <tt><a
|
||||
href="http://clang.llvm.org/doxygen/MemRegion_8h-source.html">MemRegion.h</a></tt>.
|
||||
At the root of the region hierarchy is the class <tt>MemRegion</tt> with
|
||||
specific subclasses refining the region concept for variables, heap allocated
|
||||
memory, and so forth.</li> <li>The modeling of binding of values to regions. For
|
||||
example, modeling the value stored to a local variable <tt>x</tt> consists of
|
||||
recording the binding between the region for <tt>x</tt> (which represents the
|
||||
raw memory associated with <tt>x</tt>) and the value stored to <tt>x</tt>. This
|
||||
binding relationship is captured with the notion of "symbolic
|
||||
stores."</li> </ul>
|
||||
|
||||
<p>Symbolic stores, which can be thought of as representing the relation
|
||||
<tt>regions -> values</tt>, are implemented by subclasses of the
|
||||
<tt>StoreManager</tt> class (<tt><a
|
||||
href="http://clang.llvm.org/doxygen/Store_8h-source.html">Store.h</a></tt>). A
|
||||
particular StoreManager implementation has complete flexibility concerning the
|
||||
following:
|
||||
|
||||
<ul>
|
||||
<li><em>How</em> to model the binding between regions and values</li>
|
||||
<li><em>What</em> bindings are recorded
|
||||
</ul>
|
||||
|
||||
<p>Together, both points allow different StoreManagers to tradeoff between
|
||||
different levels of analysis precision and scalability concerning the reasoning
|
||||
of program memory. Meanwhile, the core path-sensitive engine makes no
|
||||
assumptions about either points, and queries a StoreManager about the bindings
|
||||
to a memory region through a generic interface that all StoreManagers share. If
|
||||
a particular StoreManager cannot reason about the potential bindings of a given
|
||||
memory region (e.g., '<tt>BasicStoreManager</tt>' does not reason about fields
|
||||
of structures) then the StoreManager can simply return 'unknown' (represented by
|
||||
'<tt>UnknownVal</tt>') for a particular region-binding. This separation of
|
||||
concerns not only isolates the core analysis engine from the details of
|
||||
reasoning about program memory but also facilities the option of a client of the
|
||||
path-sensitive engine to easily swap in different StoreManager implementations
|
||||
that internally reason about program memory in very different ways.</pp>
|
||||
|
||||
<p>The rest of this document is divided into two parts. We first discuss region
|
||||
taxonomy and the semantics of regions. We then discuss the StoreManager
|
||||
interface, and details of how the currently available StoreManager classes
|
||||
implement region bindings.</p>
|
||||
|
||||
<h2 id="regions">Memory Regions and Region Taxonomy</h2>
|
||||
|
||||
<h3>Pointers</h3>
|
||||
|
||||
<p>Before talking about the memory regions, we would talk about the pointers
|
||||
since memory regions are essentially used to represent pointer values.</p>
|
||||
|
||||
<p>The pointer is a type of values. Pointer values have two semantic aspects.
|
||||
One is its physical value, which is an address or location. The other is the
|
||||
type of the memory object residing in the address.</p>
|
||||
|
||||
<p>Memory regions are designed to abstract these two properties of the pointer.
|
||||
The physical value of a pointer is represented by MemRegion pointers. The rvalue
|
||||
type of the region corresponds to the type of the pointee object.</p>
|
||||
|
||||
<p>One complication is that we could have different view regions on the same
|
||||
memory chunk. They represent the same memory location, but have different
|
||||
abstract location, i.e., MemRegion pointers. Thus we need to canonicalize the
|
||||
abstract locations to get a unique abstract location for one physical
|
||||
location.</p>
|
||||
|
||||
<p>Furthermore, these different view regions may or may not represent memory
|
||||
objects of different types. Some different types are semantically the same,
|
||||
for example, 'struct s' and 'my_type' are the same type.</p>
|
||||
|
||||
<pre>
|
||||
struct s;
|
||||
typedef struct s my_type;
|
||||
</pre>
|
||||
|
||||
<p>But <tt>char</tt> and <tt>int</tt> are not the same type in the code below:</p>
|
||||
|
||||
<pre>
|
||||
void *p;
|
||||
int *q = (int*) p;
|
||||
char *r = (char*) p;
|
||||
</pre
|
||||
|
||||
<p>Thus we need to canonicalize the MemRegion which is used in binding and
|
||||
retrieving.</p>
|
||||
|
||||
<h3>Regions</h3>
|
||||
<p>Region is the entity used to model pointer values. A Region has the following
|
||||
properties:</p>
|
||||
|
||||
<ul>
|
||||
<li>Kind</li>
|
||||
|
||||
<li>ObjectType: the type of the object residing on the region.</li>
|
||||
|
||||
<li>LocationType: the type of the pointer value that the region corresponds to.
|
||||
Usually this is the pointer to the ObjectType. But sometimes we want to cache
|
||||
this type explicitly, for example, for a CodeTextRegion.</li>
|
||||
|
||||
<li>StartLocation</li>
|
||||
|
||||
<li>EndLocation</li>
|
||||
</ul>
|
||||
|
||||
<h3>Symbolic Regions</h3>
|
||||
|
||||
<p>A symbolic region is a map of the concept of symbolic values into the domain
|
||||
of regions. It is the way that we represent symbolic pointers. Whenever a
|
||||
symbolic pointer value is needed, a symbolic region is created to represent
|
||||
it.</p>
|
||||
|
||||
<p>A symbolic region has no type. It wraps a SymbolData. But sometimes we have
|
||||
type information associated with a symbolic region. For this case, a
|
||||
TypedViewRegion is created to layer the type information on top of the symbolic
|
||||
region. The reason we do not carry type information with the symbolic region is
|
||||
that the symbolic regions can have no type. To be consistent, we don't let them
|
||||
to carry type information.</p>
|
||||
|
||||
<p>Like a symbolic pointer, a symbolic region may be NULL, has unknown extent,
|
||||
and represents a generic chunk of memory.</p>
|
||||
|
||||
<p><em><b>NOTE</b>: We plan not to use loc::SymbolVal in RegionStore and remove it
|
||||
gradually.</em></p>
|
||||
|
||||
<p>Symbolic regions get their rvalue types through the following ways:</p>
|
||||
|
||||
<ul>
|
||||
<li>Through the parameter or global variable that points to it, e.g.:
|
||||
<pre>
|
||||
void f(struct s* p) {
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>The symbolic region pointed to by <tt>p</tt> has type <tt>struct
|
||||
s</tt>.</p></li>
|
||||
|
||||
<li>Through explicit or implicit casts, e.g.:
|
||||
<pre>
|
||||
void f(void* p) {
|
||||
struct s* q = (struct s*) p;
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>We attach the type information to the symbolic region lazily. For the first
|
||||
case above, we create the <tt>TypedViewRegion</tt> only when the pointer is
|
||||
actually used to access the pointee memory object, that is when the element or
|
||||
field region is created. For the cast case, the <tt>TypedViewRegion</tt> is
|
||||
created when visiting the <tt>CastExpr</tt>.</p>
|
||||
|
||||
<p>The reason for doing lazy typing is that symbolic regions are sometimes only
|
||||
used to do location comparison.</p>
|
||||
|
||||
<h3>Pointer Casts</h3>
|
||||
|
||||
<p>Pointer casts allow people to impose different 'views' onto a chunk of
|
||||
memory.</p>
|
||||
|
||||
<p>Usually we have two kinds of casts. One kind of casts cast down with in the
|
||||
type hierarchy. It imposes more specific views onto more generic memory regions.
|
||||
The other kind of casts cast up with in the type hierarchy. It strips away more
|
||||
specific views on top of the more generic memory regions.</p>
|
||||
|
||||
<p>We simulate the down casts by layering another <tt>TypedViewRegion</tt> on
|
||||
top of the original region. We simulate the up casts by striping away the top
|
||||
<tt>TypedViewRegion</tt>. Down casts is usually simple. For up casts, if the
|
||||
there is no <tt>TypedViewRegion</tt> to be stripped, we return the original
|
||||
region. If the underlying region is of the different type than the cast-to type,
|
||||
we flag an error state.</p>
|
||||
|
||||
<p>For toll-free bridging casts, we return the original region.</p>
|
||||
|
||||
<p>We can set up a partial order for pointer types, with the most general type
|
||||
<tt>void*</tt> at the top. The partial order forms a tree with <tt>void*</tt> as
|
||||
its root node.</p>
|
||||
|
||||
<p>Every <tt>MemRegion</tt> has a root position in the type tree. For example,
|
||||
the pointee region of <tt>void *p</tt> has its root position at the root node of
|
||||
the tree. <tt>VarRegion</tt> of <tt>int x</tt> has its root position at the 'int
|
||||
type' node.</p>
|
||||
|
||||
<p><tt>TypedViewRegion</tt> is used to move the region down or up in the tree.
|
||||
Moving down in the tree adds a <tt>TypedViewRegion</tt>. Moving up in the tree
|
||||
removes a <Tt>TypedViewRegion</tt>.</p>
|
||||
|
||||
<p>Do we want to allow moving up beyond the root position? This happens
|
||||
when:</p> <pre> int x; void *p = &x; </pre>
|
||||
|
||||
<p>The region of <tt>x</tt> has its root position at 'int*' node. the cast to
|
||||
void* moves that region up to the 'void*' node. I propose to not allow such
|
||||
casts, and assign the region of <tt>x</tt> for <tt>p</tt>.</p>
|
||||
|
||||
<p>Another non-ideal case is that people might cast to a non-generic pointer
|
||||
from another non-generic pointer instead of first casting it back to the generic
|
||||
pointer. Direct handling of this case would result in multiple layers of
|
||||
TypedViewRegions. This enforces an incorrect semantic view to the region,
|
||||
because we can only have one typed view on a region at a time. To avoid this
|
||||
inconsistency, before casting the region, we strip the TypedViewRegion, then do
|
||||
the cast. In summary, we only allow one layer of TypedViewRegion.</p>
|
||||
|
||||
<h3>Region Bindings</h3>
|
||||
|
||||
<p>The following region kinds are boundable: VarRegion, CompoundLiteralRegion,
|
||||
StringRegion, ElementRegion, FieldRegion, and ObjCIvarRegion.</p>
|
||||
|
||||
<p>When binding regions, we perform canonicalization on element regions and field
|
||||
regions. This is because we can have different views on the same region, some
|
||||
of which are essentially the same view with different sugar type names.</p>
|
||||
|
||||
<p>To canonicalize a region, we get the canonical types for all TypedViewRegions
|
||||
along the way up to the root region, and make new TypedViewRegions with those
|
||||
canonical types.</p>
|
||||
|
||||
<p>For Objective-C and C++, perhaps another canonicalization rule should be
|
||||
added: for FieldRegion, the least derived class that has the field is used as
|
||||
the type of the super region of the FieldRegion.</p>
|
||||
|
||||
<p>All bindings and retrievings are done on the canonicalized regions.</p>
|
||||
|
||||
<p>Canonicalization is transparent outside the region store manager, and more
|
||||
specifically, unaware outside the Bind() and Retrieve() method. We don't need to
|
||||
consider region canonicalization when doing pointer cast.</p>
|
||||
|
||||
<h3>Constraint Manager</h3>
|
||||
|
||||
<p>The constraint manager reasons about the abstract location of memory objects.
|
||||
We can have different views on a region, but none of these views changes the
|
||||
location of that object. Thus we should get the same abstract location for those
|
||||
regions.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
647
docs/BlockImplementation.txt
Normal file
647
docs/BlockImplementation.txt
Normal file
@ -0,0 +1,647 @@
|
||||
Block Implementation Specification
|
||||
|
||||
Copyright 2008-2009 Apple, Inc.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
0. History
|
||||
|
||||
2008/7/14 - created
|
||||
2008/8/21 - revised, C++
|
||||
2008/9/24 - add NULL isa field to __block storage
|
||||
2008/10/1 - revise block layout to use a static descriptor structure
|
||||
2008/10/6 - revise block layout to use an unsigned long int flags
|
||||
2008/10/28 - specify use of _Block_object_assign/dispose for all "Object" types in helper functions
|
||||
2008/10/30 - revise new layout to have invoke function in same place
|
||||
2008/10/30 - add __weak support
|
||||
|
||||
This document describes the Apple ABI implementation specification of Blocks.
|
||||
|
||||
1. High Level
|
||||
|
||||
A Block consists of a structure of the following form:
|
||||
|
||||
struct Block_literal_1 {
|
||||
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(void *, ...);
|
||||
struct Block_descriptor_1 {
|
||||
unsigned long int reserved; // NULL
|
||||
unsigned long int size; // sizeof(struct Block_literal_1)
|
||||
// optional helper functions
|
||||
void (*copy_helper)(void *dst, void *src);
|
||||
void (*dispose_helper)(void *src);
|
||||
} *descriptor;
|
||||
// imported variables
|
||||
};
|
||||
|
||||
The following flags bits are used by the compiler:
|
||||
|
||||
enum {
|
||||
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
|
||||
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
|
||||
BLOCK_IS_GLOBAL = (1 << 28),
|
||||
BLOCK_HAS_DESCRIPTOR = (1 << 29), // interim until complete world build is accomplished
|
||||
};
|
||||
|
||||
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.
|
||||
|
||||
When a Block literal expression is evaluated the stack based structure is initialized as follows:
|
||||
|
||||
1) static descriptor structure is declared and initialized as follows:
|
||||
1a) the invoke function pointer is set to a function that takes the Block structure as its first argument and the rest of the arguments (if any) to the Block and executes the Block compound statement.
|
||||
1b) the size field is set to the size of the following Block literal structure.
|
||||
1c) the copy_helper and dispose_helper function pointers are set to respective helper functions if they are required by the Block literal
|
||||
2) a stack (or global) Block literal data structure is created and initialized as follows:
|
||||
2a) the isa field is set to the address of the external _NSConcreteStackBlock, which is a block of uninitialized memory supplied in libSystem, or _NSConcreteGlobalBlock if this is a static or file level block literal.
|
||||
2) The flags field is set to zero unless there are variables imported into the block that need helper functions for program level Block_copy() and Block_release() operations, in which case the (1<<25) flags bit is set.
|
||||
|
||||
As an example, the Block literal expression
|
||||
^ { printf("hello world\n"); }
|
||||
would cause to be created on a 32-bit system:
|
||||
|
||||
struct __block_literal_1 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_1 *);
|
||||
struct __block_descriptor_1 *descriptor;
|
||||
};
|
||||
|
||||
void __block_invoke_1(struct __block_literal_1 *_block) {
|
||||
printf("hello world\n");
|
||||
}
|
||||
|
||||
static struct __block_descriptor_1 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 };
|
||||
|
||||
and where the block literal appeared
|
||||
|
||||
struct __block_literal_1 _block_literal = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<29), <uninitialized>,
|
||||
__block_invoke_1,
|
||||
&__block_descriptor_1
|
||||
};
|
||||
|
||||
Blocks import other Block references, const copies of other variables, and variables marked __block. In Objective-C variables may additionally be objects.
|
||||
|
||||
When a Block literal expression used as the initial value of a global or static local variable it is initialized as follows:
|
||||
struct __block_literal_1 __block_literal_1 = {
|
||||
&_NSConcreteGlobalBlock,
|
||||
(1<<28)|(1<<29), <uninitialized>,
|
||||
__block_invoke_1,
|
||||
&__block_descriptor_1
|
||||
};
|
||||
that is, a different address is provided as the first value and a particular (1<<28) bit is set in the flags field, and otherwise it is the same as for stack based Block literals. This is an optimization that can be used for any Block literal that imports no const or __block storage variables.
|
||||
|
||||
|
||||
2. Imported Variables
|
||||
|
||||
Variables of "auto" storage class are imported as const copies. Variables of "__block" storage class are imported as a pointer to an enclosing data structure. Global variables are simply referenced and not considered as imported.
|
||||
|
||||
2.1 Imported const copy variables
|
||||
|
||||
Automatic storage variables not marked with __block are imported as const copies.
|
||||
|
||||
The simplest example is that of importing a variable of type int.
|
||||
|
||||
int x = 10;
|
||||
void (^vv)(void) = ^{ printf("x is %d\n", x); }
|
||||
x = 11;
|
||||
vv();
|
||||
|
||||
would be compiled
|
||||
|
||||
struct __block_literal_2 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_2 *);
|
||||
struct __block_descriptor_2 *descriptor;
|
||||
const int x;
|
||||
};
|
||||
|
||||
void __block_invoke_2(struct __block_literal_2 *_block) {
|
||||
printf("x is %d\n", _block->x);
|
||||
}
|
||||
|
||||
static struct __block_descriptor_2 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
} __block_descriptor_2 = { 0, sizeof(struct __block_literal_2) };
|
||||
|
||||
and
|
||||
|
||||
struct __block_literal_2 __block_literal_2 = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<29), <uninitialized>,
|
||||
__block_invoke_2,
|
||||
&__block_descriptor_2,
|
||||
x
|
||||
};
|
||||
|
||||
In summary, scalars, structures, unions, and function pointers are generally imported as const copies with no need for helper functions.
|
||||
|
||||
2.2 Imported const copy of Block reference
|
||||
|
||||
The first case where copy and dispose helper functions are required is for the case of when a block itself is imported. In this case both a copy_helper function and a dispose_helper function are needed. The copy_helper function is passed both the existing stack based pointer and the pointer to the new heap version and should call back into the runtime to actually do the copy operation on the imported fields within the block. The runtime functions are all described in Section 5.0 Runtime Helper Functions.
|
||||
|
||||
An example:
|
||||
|
||||
void (^existingBlock)(void) = ...;
|
||||
void (^vv)(void) = ^{ existingBlock(); }
|
||||
vv();
|
||||
|
||||
struct __block_literal_3 {
|
||||
...; // existing block
|
||||
};
|
||||
|
||||
struct __block_literal_4 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_4 *);
|
||||
struct __block_literal_3 *const existingBlock;
|
||||
};
|
||||
|
||||
void __block_invoke_4(struct __block_literal_2 *_block) {
|
||||
__block->existingBlock->invoke(__block->existingBlock);
|
||||
}
|
||||
|
||||
void __block_copy_4(struct __block_literal_4 *dst, struct __block_literal_4 *src) {
|
||||
//_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
|
||||
_Block_object_assign(&dst->existingBlock, src->existingBlock, BLOCK_FIELD_IS_BLOCK);
|
||||
}
|
||||
|
||||
void __block_dispose_4(struct __block_literal_4 *src) {
|
||||
// was _Block_destroy
|
||||
_Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
|
||||
}
|
||||
|
||||
static struct __block_descriptor_4 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
void (*copy_helper)(struct __block_literal_4 *dst, struct __block_literal_4 *src);
|
||||
void (*dispose_helper)(struct __block_literal_4 *);
|
||||
} __block_descriptor_4 = {
|
||||
0,
|
||||
sizeof(struct __block_literal_4),
|
||||
__block_copy_4,
|
||||
__block_dispose_4,
|
||||
};
|
||||
|
||||
and where it is used
|
||||
|
||||
struct __block_literal_4 _block_literal = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<25)|(1<<29), <uninitialized>
|
||||
__block_invoke_4,
|
||||
& __block_descriptor_4
|
||||
existingBlock,
|
||||
};
|
||||
|
||||
2.2.1 Importing __attribute__((NSObject)) variables.
|
||||
|
||||
GCC introduces __attribute__((NSObject)) on structure pointers to mean "this is an object". This is useful because many low level data structures are declared as opaque structure pointers, e.g. CFStringRef, CFArrayRef, etc. When used from C, however, these are still really objects and are the second case where that requires copy and dispose helper functions to be generated. The copy helper functions generated by the compiler should use the _Block_object_assign runtime helper function and in the dispose helper the _Block_object_dispose runtime helper function should be called.
|
||||
|
||||
For example, block xyzzy in the following
|
||||
|
||||
struct Opaque *__attribute__((NSObject)) objectPointer = ...;
|
||||
...
|
||||
void (^xyzzy)(void) = ^{ CFPrint(objectPointer); };
|
||||
|
||||
would have helper functions
|
||||
|
||||
void __block_copy_xyzzy(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
|
||||
_Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
|
||||
}
|
||||
|
||||
void __block_dispose_xyzzy(struct __block_literal_5 *src) {
|
||||
_Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
|
||||
}
|
||||
|
||||
generated.
|
||||
|
||||
|
||||
2.3 Imported __block marked variables.
|
||||
|
||||
2.3.1 Layout of __block marked variables
|
||||
|
||||
The compiler must embed variables that are marked __block in a specialized structure of the form:
|
||||
|
||||
struct _block_byref_xxxx {
|
||||
void *isa;
|
||||
struct Block_byref *forwarding;
|
||||
int flags; //refcount;
|
||||
int size;
|
||||
typeof(marked_variable) marked_variable;
|
||||
};
|
||||
|
||||
Variables of certain types require helper functions for when Block_copy() and Block_release() are performed upon a referencing Block. At the "C" level only variables that are of type Block or ones that have __attribute__((NSObject)) marked require helper functions. In Objective-C objects require helper functions and in C++ stack based objects require helper functions. Variables that require helper functions use the form:
|
||||
|
||||
struct _block_byref_xxxx {
|
||||
void *isa;
|
||||
struct _block_byref_xxxx *forwarding;
|
||||
int flags; //refcount;
|
||||
int size;
|
||||
// helper functions called via Block_copy() and Block_release()
|
||||
void (*byref_keep)(void *dst, void *src);
|
||||
void (*byref_dispose)(void *);
|
||||
typeof(marked_variable) marked_variable;
|
||||
};
|
||||
|
||||
The structure is initialized such that
|
||||
a) the forwarding pointer is set to the beginning of its enclosing structure,
|
||||
b) the size field is initialized to the total size of the enclosing structure,
|
||||
c) the flags field is set to either 0 if no helper functions are needed or (1<<25) if they are,
|
||||
d) the helper functions are initialized (if present)
|
||||
e) the variable itself is set to its initial value.
|
||||
f) the isa field is set to NULL
|
||||
|
||||
2.3.2 Access to __block variables from within its lexical scope.
|
||||
|
||||
In order to "move" the variable to the heap upon a copy_helper operation the compiler must rewrite access to such a variable to be indirect through the structures forwarding pointer. For example:
|
||||
|
||||
int __block i = 10;
|
||||
i = 11;
|
||||
|
||||
would be rewritten to be:
|
||||
|
||||
struct _block_byref_i {
|
||||
void *isa;
|
||||
struct _block_byref_i *forwarding;
|
||||
int flags; //refcount;
|
||||
int size;
|
||||
int captured_i;
|
||||
} i = { NULL, &i, 0, sizeof(struct _block_byref_i), 11;
|
||||
|
||||
i.forwarding->captured_i = 11;
|
||||
|
||||
In the case of a Block reference variable being marked __block the helper code generated must use the _Block_object_assign and _Block_object_dispose routines supplied by the runtime to make the copies. For example:
|
||||
|
||||
__block void (voidBlock)(void) = blockA;
|
||||
voidBlock = blockB;
|
||||
|
||||
would translate into
|
||||
|
||||
struct _block_byref_voidBlock {
|
||||
void *isa;
|
||||
struct _block_byref_voidBlock *forwarding;
|
||||
int flags; //refcount;
|
||||
int size;
|
||||
void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
|
||||
void (*byref_dispose)(struct _block_byref_voidBlock *);
|
||||
void (^captured_voidBlock)(void);
|
||||
};
|
||||
|
||||
void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
|
||||
//_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
|
||||
_Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
|
||||
}
|
||||
|
||||
void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
|
||||
//_Block_destroy(param->captured_voidBlock, 0);
|
||||
_Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
|
||||
|
||||
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 };
|
||||
|
||||
voidBlock.forwarding->captured_voidBlock = blockB;
|
||||
|
||||
|
||||
2.3.3 Importing __block variables into Blocks
|
||||
|
||||
A Block that uses a __block variable in its compound statement body must import the variable and emit copy_helper and dispose_helper helper functions that, in turn, call back into the runtime to actually copy or release the byref data block using the functions _Block_object_assign and _Block_object_dispose.
|
||||
|
||||
For example:
|
||||
|
||||
int __block i = 2;
|
||||
functioncall(^{ i = 10; });
|
||||
|
||||
would translate to
|
||||
|
||||
struct _block_byref_i {
|
||||
void *isa; // set to NULL
|
||||
struct _block_byref_voidBlock *forwarding;
|
||||
int flags; //refcount;
|
||||
int size;
|
||||
void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
|
||||
void (*byref_dispose)(struct _block_byref_i *);
|
||||
int captured_i;
|
||||
};
|
||||
|
||||
|
||||
struct __block_literal_5 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_5 *);
|
||||
struct __block_descriptor_5 *descriptor;
|
||||
struct _block_byref_i *i_holder;
|
||||
};
|
||||
|
||||
void __block_invoke_5(struct __block_literal_5 *_block) {
|
||||
_block->forwarding->captured_i = 10;
|
||||
}
|
||||
|
||||
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
|
||||
//_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
|
||||
_Block_object_assign(&dst->captured_i, src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
|
||||
}
|
||||
|
||||
void __block_dispose_5(struct __block_literal_5 *src) {
|
||||
//_Block_byref_release(src->captured_i);
|
||||
_Block_object_dispose(src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
|
||||
}
|
||||
|
||||
static struct __block_descriptor_5 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
|
||||
void (*dispose_helper)(struct __block_literal_5 *);
|
||||
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };
|
||||
|
||||
and
|
||||
|
||||
struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
|
||||
struct __block_literal_5 _block_literal = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<25)|(1<<29), <uninitialized>,
|
||||
__block_invoke_5,
|
||||
&__block_descriptor_5,
|
||||
2,
|
||||
};
|
||||
|
||||
2.3.4 Importing __attribute__((NSObject)) __block variables
|
||||
|
||||
A __block variable that is also marked __attribute__((NSObject)) should have byref_keep and byref_dispose helper functions that use _Block_object_assign and _Block_object_dispose.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
2.3.6 Nesting
|
||||
|
||||
Blocks may contain Block literal expressions. Any variables used within inner blocks are imported into all enclosing Block scopes even if the variables are not used. This includes const imports as well as __block variables.
|
||||
|
||||
3. Objective C Extensions to Blocks
|
||||
|
||||
3.1 Importing Objects
|
||||
|
||||
Objects should be treated as __attribute__((NSObject)) variables; all copy_helper, dispose_helper, byref_keep, and byref_dispose helper functions should use _Block_object_assign and _Block_object_dispose. There should be no code generated that uses -retain or -release methods.
|
||||
|
||||
|
||||
3.2 Blocks as Objects
|
||||
|
||||
The compiler will treat Blocks as objects when synthesizing property setters and getters, will characterize them as objects when generating garbage collection strong and weak layout information in the same manner as objects, and will issue strong and weak write-barrier assignments in the same manner as objects.
|
||||
|
||||
3.3 __weak __block Support
|
||||
|
||||
Objective-C (and Objective-C++) support the __weak attribute on __block variables. Under normal circumstances the compiler uses the Objective-C runtime helper support functions objc_assign_weak and objc_read_weak. Both should continue to be used for all reads and writes of __weak __block variables:
|
||||
objc_read_weak(&block->byref_i->forwarding->i)
|
||||
|
||||
The __weak variable is stored in a _block_byref_xxxx structure and the Block has copy and dispose helpers for this structure that call:
|
||||
_Block_object_assign(&dest->_block_byref_i, src-> _block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
|
||||
and
|
||||
_Block_object_dispose(src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
|
||||
|
||||
|
||||
In turn, the block_byref copy support helpers distinguish between whether the __block variable is a Block or not and should either call:
|
||||
_Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_OBJECT | BLOCK_BYREF_CALLER);
|
||||
for something declared as an object or
|
||||
_Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
|
||||
for something declared as a Block.
|
||||
|
||||
A full example follows:
|
||||
|
||||
|
||||
__block __weak id obj = <initialization expression>;
|
||||
functioncall(^{ [obj somemessage]; });
|
||||
|
||||
would translate to
|
||||
|
||||
struct _block_byref_obj {
|
||||
void *isa; // uninitialized
|
||||
struct _block_byref_obj *forwarding;
|
||||
int flags; //refcount;
|
||||
int size;
|
||||
void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
|
||||
void (*byref_dispose)(struct _block_byref_i *);
|
||||
int captured_obj;
|
||||
};
|
||||
|
||||
void _block_byref_obj_keep(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
|
||||
//_Block_copy_assign(&dst->captured_obj, src->captured_obj, 0);
|
||||
_Block_object_assign(&dst->captured_obj, src->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
|
||||
}
|
||||
|
||||
void _block_byref_obj_dispose(struct _block_byref_voidBlock *param) {
|
||||
//_Block_destroy(param->captured_obj, 0);
|
||||
_Block_object_dispose(param->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
|
||||
};
|
||||
|
||||
for the block byref part and
|
||||
|
||||
struct __block_literal_5 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_5 *);
|
||||
struct __block_descriptor_5 *descriptor;
|
||||
struct _block_byref_obj *byref_obj;
|
||||
};
|
||||
|
||||
void __block_invoke_5(struct __block_literal_5 *_block) {
|
||||
[objc_read_weak(&_block->byref_obj->forwarding->captured_obj) somemessage];
|
||||
}
|
||||
|
||||
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
|
||||
//_Block_byref_assign_copy(&dst->byref_obj, src->byref_obj);
|
||||
_Block_object_assign(&dst->byref_obj, src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
|
||||
}
|
||||
|
||||
void __block_dispose_5(struct __block_literal_5 *src) {
|
||||
//_Block_byref_release(src->byref_obj);
|
||||
_Block_object_dispose(src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
|
||||
}
|
||||
|
||||
static struct __block_descriptor_5 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
|
||||
void (*dispose_helper)(struct __block_literal_5 *);
|
||||
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5), __block_copy_5, __block_dispose_5 };
|
||||
|
||||
and within the compound statement:
|
||||
|
||||
struct _block_byref_obj obj = {( .forwarding=&obj, .flags=(1<<25), .size=sizeof(struct _block_byref_obj),
|
||||
.byref_keep=_block_byref_obj_keep, .byref_dispose=_block_byref_obj_dispose,
|
||||
.captured_obj = <initialization expression> )};
|
||||
|
||||
struct __block_literal_5 _block_literal = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<25)|(1<<29), <uninitialized>,
|
||||
__block_invoke_5,
|
||||
&__block_descriptor_5,
|
||||
&obj, // a reference to the on-stack structure containing "captured_obj"
|
||||
};
|
||||
|
||||
|
||||
functioncall(_block_literal->invoke(&_block_literal));
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
{
|
||||
FOO foo;
|
||||
void (^block)(void) = ^{ printf("%d\n", foo.value()); };
|
||||
}
|
||||
|
||||
The compiler would synthesize
|
||||
|
||||
struct __block_literal_10 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_10 *);
|
||||
struct __block_descriptor_10 *descriptor;
|
||||
const FOO foo;
|
||||
};
|
||||
|
||||
void __block_invoke_10(struct __block_literal_10 *_block) {
|
||||
printf("%d\n", _block->foo.value());
|
||||
}
|
||||
|
||||
void __block_literal_10(struct __block_literal_10 *dst, struct __block_literal_10 *src) {
|
||||
comp_ctor(&dst->foo, &src->foo);
|
||||
}
|
||||
|
||||
void __block_dispose_10(struct __block_literal_10 *src) {
|
||||
comp_dtor(&src->foo);
|
||||
}
|
||||
|
||||
static struct __block_descriptor_10 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
void (*copy_helper)(struct __block_literal_10 *dst, struct __block_literal_10 *src);
|
||||
void (*dispose_helper)(struct __block_literal_10 *);
|
||||
} __block_descriptor_10 = { 0, sizeof(struct __block_literal_10), __block_copy_10, __block_dispose_10 };
|
||||
|
||||
and the code would be:
|
||||
{
|
||||
FOO foo;
|
||||
comp_ctor(&foo); // default constructor
|
||||
struct __block_literal_10 _block_literal = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<25)|(1<<26)|(1<<29), <uninitialized>,
|
||||
__block_invoke_10,
|
||||
&__block_descriptor_10,
|
||||
};
|
||||
comp_ctor(&_block_literal->foo, &foo); // const copy into stack version
|
||||
struct __block_literal_10 &block = &_block_literal; // assign literal to block variable
|
||||
block->invoke(block); // invoke block
|
||||
comp_dtor(&_block_literal->foo); // destroy stack version of const block copy
|
||||
comp_dtor(&foo); // destroy original version
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
The runtime helper functions are described in /usr/local/include/Block_private.h. To summarize their use, a block requires copy/dispose helpers if it imports any block variables, __block storage variables, __attribute__((NSObject)) variables, or C++ const copied objects with constructor/destructors. The (1<<26) bit is set and functions are generated.
|
||||
|
||||
The block copy helper function should, for each of the variables of the type mentioned above, call
|
||||
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<appropo>);
|
||||
in the copy helper and
|
||||
_Block_object_dispose(->target, BLOCK_FIELD_<appropo>);
|
||||
in the dispose helper where
|
||||
<appropo> is
|
||||
|
||||
enum {
|
||||
BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
|
||||
BLOCK_FIELD_IS_BLOCK = 7, // a block variable
|
||||
BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
|
||||
|
||||
BLOCK_FIELD_IS_WEAK = 16, // declared __weak
|
||||
|
||||
BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
|
||||
};
|
||||
|
||||
and of course the CTORs/DTORs for const copied C++ objects.
|
||||
|
||||
The block_byref data structure similarly requires copy/dispose helpers for block variables, __attribute__((NSObject)) variables, or C++ const copied objects with constructor/destructors, and again the (1<<26) bit is set and functions are generated in the same manner.
|
||||
|
||||
Under ObjC we allow __weak as an attribute on __block variables, and this causes the addition of BLOCK_FIELD_IS_WEAK orred onto the BLOCK_FIELD_IS_BYREF flag when copying the block_byref structure in the block copy helper, and onto the BLOCK_FIELD_<appropo> field within the block_byref copy/dispose helper calls.
|
||||
|
||||
The prototypes, and summary, of the helper functions are
|
||||
|
||||
/* Certain field types require runtime assistance when being copied to the heap. The following function is used
|
||||
to copy fields of types: blocks, pointers to byref structures, and objects (including __attribute__((NSObject)) pointers.
|
||||
BLOCK_FIELD_IS_WEAK is orthogonal to the other choices which are mutually exclusive.
|
||||
Only in a Block copy helper will one see BLOCK_FIELD_IS_BYREF.
|
||||
*/
|
||||
void _Block_object_assign(void *destAddr, const void *object, const int flags);
|
||||
|
||||
/* Similarly a compiler generated dispose helper needs to call back for each field of the byref data structure.
|
||||
(Currently the implementation only packs one field into the byref structure but in principle there could be more).
|
||||
The same flags used in the copy helper should be used for each call generated to this function:
|
||||
*/
|
||||
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);
|
||||
|
||||
|
165
docs/BlockLanguageSpec.txt
Normal file
165
docs/BlockLanguageSpec.txt
Normal file
@ -0,0 +1,165 @@
|
||||
Language Specification for Blocks
|
||||
|
||||
2008/2/25 — created
|
||||
2008/7/28 — revised, __block syntax
|
||||
2008/8/13 — revised, Block globals
|
||||
2008/8/21 — revised, C++ elaboration
|
||||
2008/11/1 — revised, __weak support
|
||||
2009/1/12 — revised, explicit return types
|
||||
2009/2/10 — revised, __block objects need retain
|
||||
|
||||
Copyright 2008-2009 Apple, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
The Block Type
|
||||
|
||||
A new derived type is introduced to C and, by extension, Objective-C, C++, and Objective-C++. Like function types, the Block type is a pair consisting of a result value type and a list of parameter types very similar to a function type. Blocks are intended to be used much like functions with the key distinction being that in addition to executable code they also contain various variable bindings to automatic (stack) or managed (heap) memory.
|
||||
|
||||
The abstract declarator int (^)(char, float) describes a reference to a Block that, when invoked, takes two parameters, the first of type char and the second of type float, and returns a value of type int. The Block referenced is of opaque data that may reside in automatic (stack) memory, global memory, or heap memory.
|
||||
|
||||
|
||||
Block Variable Declarations
|
||||
|
||||
A variable with Block type is declared using function pointer style notation substituting ^ for *. The following are valid Block variable declarations:
|
||||
void (^blockReturningVoidWithVoidArgument)(void);
|
||||
int (^blockReturningIntWithIntAndCharArguments)(int, char);
|
||||
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
|
||||
|
||||
Variadic ... arguments are supported. [variadic.c] A Block that takes no arguments must specify void in the argument list [voidarg.c]. An empty parameter list does not represent, as K&R provide, an unspecified argument list. Note: both gcc and clang support K&R style as a convenience.
|
||||
|
||||
A Block reference may be cast to a pointer of arbitrary type and vice versa. [cast.c] A Block reference may not be dereferenced via the pointer dereference operator *, and thus a Block's size may not be computed at compile time. [sizeof.c]
|
||||
|
||||
|
||||
Block Literal Expressions
|
||||
|
||||
A Block literal expression produces a reference to a Block. It is introduced by the use of the ^ token as a unary operator.
|
||||
Block_literal_expression ::= ^ block_decl compound_statement_body
|
||||
block_decl ::=
|
||||
block_decl ::= parameter_list
|
||||
block_decl ::= type_expression
|
||||
|
||||
...where type expression is extended to allow ^ as a Block reference (pointer) where * is allowed as a function reference (pointer).
|
||||
|
||||
The following Block literal:
|
||||
^ void (void) { printf("hello world\n"); }
|
||||
|
||||
...produces a reference to a Block with no arguments with no return value.
|
||||
|
||||
The return type is optional and is inferred from the return statements. If the return statements return a value, they all must return a value of the same type. If there is no value returned the inferred type of the Block is void; otherwise it is the type of the return statement value.
|
||||
|
||||
If the return type is omitted and the argument list is ( void ), the ( void ) argument list may also be omitted.
|
||||
|
||||
So:
|
||||
^ ( void ) { printf("hello world\n"); }
|
||||
|
||||
...and:
|
||||
^ { printf("hello world\n"); }
|
||||
|
||||
...are exactly equivalent constructs for the same expression.
|
||||
|
||||
The type_expression extends C expression parsing to accommodate Block reference declarations as it accommodates function pointer declarations.
|
||||
|
||||
Given:
|
||||
typedef int (*pointerToFunctionThatReturnsIntWithCharArg)(char);
|
||||
pointerToFunctionThatReturnsIntWithCharArg functionPointer;
|
||||
|
||||
^ pointerToFunctionThatReturnsIntWithCharArg (float x) { return functionPointer; }
|
||||
|
||||
...and:
|
||||
^ int ((*)(float x))(char) { return functionPointer; }
|
||||
|
||||
...are equivalent expressions, as is:
|
||||
|
||||
^(float x) { return functionPointer; }
|
||||
|
||||
[returnfunctionptr.c]
|
||||
|
||||
The compound statement body establishes a new lexical scope within that of its parent. Variables used within the scope of the compound statement are bound to the Block in the normal manner with the exception of those in automatic (stack) storage. Thus one may access functions and global variables as one would expect, as well as static local variables. [testme]
|
||||
|
||||
Local automatic (stack) variables referenced within the compound statement of a Block are imported and captured by the Block as const copies. The capture (binding) is performed at the time of the Block literal expression evaluation.
|
||||
|
||||
The lifetime of variables declared in a Block is that of a function; each activation frame contains a new copy of variables declared within the local scope of the Block. Such variable declarations should be allowed anywhere [testme] rather than only when C99 parsing is requested, including for statements. [testme]
|
||||
|
||||
Block literal expressions may occur within Block literal expressions (nest) and all variables captured by any nested blocks are implicitly also captured in the scopes of their enclosing Blocks.
|
||||
|
||||
A Block literal expression may be used as the initialization value for Block variables at global or local static scope.
|
||||
|
||||
|
||||
The Invoke Operator
|
||||
|
||||
Blocks are invoked using function call syntax with a list of expression parameters of types corresponding to the declaration and returning a result type also according to the declaration. Given:
|
||||
int (^x)(char);
|
||||
void (^z)(void);
|
||||
int (^(*y))(char) = &x;
|
||||
|
||||
...the following are all legal Block invocations:
|
||||
x('a');
|
||||
(*y)('a');
|
||||
(true ? x : *y)('a')
|
||||
|
||||
|
||||
The Copy and Release Operations
|
||||
|
||||
The compiler and runtime provide copy and release operations for Block references that create and, in matched use, release allocated storage for referenced Blocks.
|
||||
|
||||
The copy operation Block_copy() is styled as a function that takes an arbitrary Block reference and returns a Block reference of the same type. The release operation, Block_release(), is styled as a function that takes an arbitrary Block reference and, if dynamically matched to a Block copy operation, allows recovery of the referenced allocated memory.
|
||||
|
||||
|
||||
The __block Storage Qualifier
|
||||
|
||||
In addition to the new Block type we also introduce a new storage qualifier, __block, for local variables. [testme: a __block declaration within a block literal] The __block storage qualifier is mutually exclusive to the existing local storage qualifiers auto, register, and static.[testme] Variables qualified by __block act as if they were in allocated storage and this storage is automatically recovered after last use of said variable. An implementation may choose an optimization where the storage is initially automatic and only "moved" to allocated (heap) storage upon a Block_copy of a referencing Block. Such variables may be mutated as normal variables are.
|
||||
|
||||
In the case where a __block variable is a Block one must assume that the __block variable resides in allocated storage and as such is assumed to reference a Block that is also in allocated storage (that it is the result of a Block_copy operation). Despite this there is no provision to do a Block_copy or a Block_release if an implementation provides initial automatic storage for Blocks. This is due to the inherent race condition of potentially several threads trying to update the shared variable and the need for synchronization around disposing of older values and copying new ones. Such synchronization is beyond the scope of this language specification.
|
||||
|
||||
|
||||
Control Flow
|
||||
|
||||
The compound statement of a Block is treated much like a function body with respect to control flow in that goto, break, and continue do not escape the Block. Exceptions are treated "normally" in that when thrown they pop stack frames until a catch clause is found.
|
||||
|
||||
|
||||
Objective-C Extensions
|
||||
|
||||
Objective-C extends the definition of a Block reference type to be that also of id. A variable or expression of Block type may be messaged or used as a parameter wherever an id may be. The converse is also true. Block references may thus appear as properties and are subject to the assign, retain, and copy attribute logic that is reserved for objects.
|
||||
|
||||
All Blocks are constructed to be Objective-C objects regardless of whether the Objective-C runtime is operational in the program or not. Blocks using automatic (stack) memory are objects and may be messaged, although they may not be assigned into __weak locations if garbage collection is enabled.
|
||||
|
||||
Within a Block literal expression within a method definition references to instance variables are also imported into the lexical scope of the compound statement. These variables are implicitly qualified as references from self, and so self is imported as a const copy. The net effect is that instance variables can be mutated.
|
||||
|
||||
The Block_copy operator retains all objects held in variables of automatic storage referenced within the Block expression (or form strong references if running under garbage collection). Object variables of __block storage type are assumed to hold normal pointers with no provision for retain and release messages.
|
||||
|
||||
Foundation defines (and supplies) -copy and -release methods for Blocks.
|
||||
|
||||
In the Objective-C and Objective-C++ languages, we allow the __weak specifier for __block variables of object type. If garbage collection is not enabled, this qualifier causes these variables to be kept without retain messages being sent. This knowingly leads to dangling pointers if the Block (or a copy) outlives the lifetime of this object.
|
||||
|
||||
In garbage collected environments, the __weak variable is set to nil when the object it references is collected, as long as the __block variable resides in the heap (either by default or via Block_copy()). The initial Apple implementation does in fact start __block variables on the stack and migrate them to the heap only as a result of a Block_copy() operation.
|
||||
|
||||
It is a runtime error to attempt to assign a reference to a stack-based Block into any storage marked __weak, including __weak __block variables.
|
||||
|
||||
|
||||
C++ Extensions
|
||||
|
||||
Block literal expressions within functions are extended to allow const use of C++ objects, pointers, or references held in automatic storage.
|
||||
|
||||
For example, given class Foo with member function fighter(void):
|
||||
Foo foo;
|
||||
Foo &fooRef = foo;
|
||||
Foo *fooPtr = &foo;
|
||||
|
||||
...a Block that used foo would import the variables as const variations:
|
||||
const Foo block_foo = foo; // const copy constructor
|
||||
const Foo &block_fooRef = fooRef;
|
||||
const Foo *block_fooPtr = fooPtr;
|
||||
|
||||
Stack-local objects are copied into a Block via a copy const constructor. If no such constructor exists, it is considered an error to reference such objects from within the Block compound statements. A destructor is run as control leaves the compound statement that contains the Block literal expression.
|
||||
|
||||
If a Block originates on the stack, a const copy constructor of the stack-based Block const copy is performed when a Block_copy operation is called; when the last Block_release (or subsequently GC) occurs, a destructor is run on the heap copy.
|
||||
|
||||
Variables declared as residing in __block storage may be initially allocated in the heap or may first appear on the stack and be copied to the heap as a result of a Block_copy() operation. When copied from the stack, a normal copy constructor is used to initialize the heap-based version from the original stack version. The destructor for a const copied object is run at the normal end of scope. The destructor for any initial stack based version is also called at normal end of scope.
|
||||
|
||||
Within a member function, access to member functions and variables is done via an implicit const copy of a this pointer.
|
||||
|
||||
Member variables that are Blocks may not be overloaded by the types of their arguments.
|
||||
|
BIN
docs/DriverArchitecture.png
Normal file
BIN
docs/DriverArchitecture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
517
docs/DriverInternals.html
Normal file
517
docs/DriverInternals.html
Normal file
@ -0,0 +1,517 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang Driver Manual</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Driver Design & Internals</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#features">Features and Goals</a></li>
|
||||
<ul>
|
||||
<li><a href="#gcccompat">GCC Compatibility</a></li>
|
||||
<li><a href="#components">Flexible</a></li>
|
||||
<li><a href="#performance">Low Overhead</a></li>
|
||||
<li><a href="#simple">Simple</a></li>
|
||||
</ul>
|
||||
<li><a href="#design">Design</a></li>
|
||||
<ul>
|
||||
<li><a href="#int_intro">Internals Introduction</a></li>
|
||||
<li><a href="#int_overview">Design Overview</a></li>
|
||||
<li><a href="#int_notes">Additional Notes</a></li>
|
||||
<ul>
|
||||
<li><a href="#int_compilation">The Compilation Object</a></li>
|
||||
<li><a href="#int_unified_parsing">Unified Parsing & Pipelining</a></li>
|
||||
<li><a href="#int_toolchain_translation">ToolChain Argument Translation</a></li>
|
||||
<li><a href="#int_unused_warnings">Unused Argument Warnings</a></li>
|
||||
</ul>
|
||||
<li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This document describes the Clang driver. The purpose of this
|
||||
document is to describe both the motivation and design goals
|
||||
for the driver, as well as details of the internal
|
||||
implementation.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="features">Features and Goals</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The Clang driver is intended to be a production quality
|
||||
compiler driver providing access to the Clang compiler and
|
||||
tools, with a command line interface which is compatible with
|
||||
the gcc driver.</p>
|
||||
|
||||
<p>Although the driver is part of and driven by the Clang
|
||||
project, it is logically a separate tool which shares many of
|
||||
the same goals as Clang:</p>
|
||||
|
||||
<p><b>Features</b>:</p>
|
||||
<ul>
|
||||
<li><a href="#gcccompat">GCC Compatibility</a></li>
|
||||
<li><a href="#components">Flexible</a></li>
|
||||
<li><a href="#performance">Low Overhead</a></li>
|
||||
<li><a href="#simple">Simple</a></li>
|
||||
</ul>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3 id="gcccompat">GCC Compatibility</h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The number one goal of the driver is to ease the adoption of
|
||||
Clang by allowing users to drop Clang into a build system
|
||||
which was designed to call GCC. Although this makes the driver
|
||||
much more complicated than might otherwise be necessary, we
|
||||
decided that being very compatible with the gcc command line
|
||||
interface was worth it in order to allow users to quickly test
|
||||
clang on their projects.</p>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3 id="components">Flexible</h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The driver was designed to be flexible and easily accomodate
|
||||
new uses as we grow the clang and LLVM infrastructure. As one
|
||||
example, the driver can easily support the introduction of
|
||||
tools which have an integrated assembler; something we hope to
|
||||
add to LLVM in the future.</p>
|
||||
|
||||
<p>Similarly, most of the driver functionality is kept in a
|
||||
library which can be used to build other tools which want to
|
||||
implement or accept a gcc like interface. </p>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3 id="performance">Low Overhead</h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The driver should have as little overhead as possible. In
|
||||
practice, we found that the gcc driver by itself incurred a
|
||||
small but meaningful overhead when compiling many small
|
||||
files. The driver doesn't do much work compared to a
|
||||
compilation, but we have tried to keep it as efficient as
|
||||
possible by following a few simple principles:</p>
|
||||
<ul>
|
||||
<li>Avoid memory allocation and string copying when
|
||||
possible.</li>
|
||||
|
||||
<li>Don't parse arguments more than once.</li>
|
||||
|
||||
<li>Provide a few simple interfaces for efficiently searching
|
||||
arguments.</li>
|
||||
</ul>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3 id="simple">Simple</h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>Finally, the driver was designed to be "as simple as
|
||||
possible", given the other goals. Notably, trying to be
|
||||
completely compatible with the gcc driver adds a significant
|
||||
amount of complexity. However, the design of the driver
|
||||
attempts to mitigate this complexity by dividing the process
|
||||
into a number of independent stages instead of a single
|
||||
monolithic task.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="design">Internal Design and Implementation</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<ul>
|
||||
<li><a href="#int_intro">Internals Introduction</a></li>
|
||||
<li><a href="#int_overview">Design Overview</a></li>
|
||||
<li><a href="#int_notes">Additional Notes</a></li>
|
||||
<li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
|
||||
</ul>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_intro">Internals Introduction</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>In order to satisfy the stated goals, the driver was designed
|
||||
to completely subsume the functionality of the gcc executable;
|
||||
that is, the driver should not need to delegate to gcc to
|
||||
perform subtasks. On Darwin, this implies that the Clang
|
||||
driver also subsumes the gcc driver-driver, which is used to
|
||||
implement support for building universal images (binaries and
|
||||
object files). This also implies that the driver should be
|
||||
able to call the language specific compilers (e.g. cc1)
|
||||
directly, which means that it must have enough information to
|
||||
forward command line arguments to child processes
|
||||
correctly.</p>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_overview">Design Overview</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The diagram below shows the significant components of the
|
||||
driver architecture and how they relate to one another. The
|
||||
orange components represent concrete data structures built by
|
||||
the driver, the green components indicate conceptually
|
||||
distinct stages which manipulate these data structures, and
|
||||
the blue components are important helper classes. </p>
|
||||
|
||||
<center>
|
||||
<a href="DriverArchitecture.png" alt="Driver Architecture Diagram">
|
||||
<img width=400 src="DriverArchitecture.png">
|
||||
</a>
|
||||
</center>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_stages">Driver Stages</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The driver functionality is conceptually divided into five stages:</p>
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
<b>Parse: Option Parsing</b>
|
||||
|
||||
<p>The command line argument strings are decomposed into
|
||||
arguments (<tt>Arg</tt> instances). The driver expects to
|
||||
understand all available options, although there is some
|
||||
facility for just passing certain classes of options
|
||||
through (like <tt>-Wl,</tt>).</p>
|
||||
|
||||
<p>Each argument corresponds to exactly one
|
||||
abstract <tt>Option</tt> definition, which describes how
|
||||
the option is parsed along with some additional
|
||||
metadata. The Arg instances themselves are lightweight and
|
||||
merely contain enough information for clients to determine
|
||||
which option they correspond to and their values (if they
|
||||
have additional parameters).</p>
|
||||
|
||||
<p>For example, a command line like "-Ifoo -I foo" would
|
||||
parse to two Arg instances (a JoinedArg and a SeparateArg
|
||||
instance), but each would refer to the same Option.</p>
|
||||
|
||||
<p>Options are lazily created in order to avoid populating
|
||||
all Option classes when the driver is loaded. Most of the
|
||||
driver code only needs to deal with options by their
|
||||
unique ID (e.g., <tt>options::OPT_I</tt>),</p>
|
||||
|
||||
<p>Arg instances themselves do not generally store the
|
||||
values of parameters. In many cases, this would
|
||||
simply result in creating unnecessary string
|
||||
copies. Instead, Arg instances are always embedded inside
|
||||
an ArgList structure, which contains the original vector
|
||||
of argument strings. Each Arg itself only needs to contain
|
||||
an index into this vector instead of storing its values
|
||||
directly.</p>
|
||||
|
||||
<p>The clang driver can dump the results of this
|
||||
stage using the <tt>-ccc-print-options</tt> flag (which
|
||||
must preceed any actual command line arguments). For
|
||||
example:</p>
|
||||
<pre>
|
||||
$ <b>clang -ccc-print-options -Xarch_i386 -fomit-frame-pointer -Wa,-fast -Ifoo -I foo t.c</b>
|
||||
Option 0 - Name: "-Xarch_", Values: {"i386", "-fomit-frame-pointer"}
|
||||
Option 1 - Name: "-Wa,", Values: {"-fast"}
|
||||
Option 2 - Name: "-I", Values: {"foo"}
|
||||
Option 3 - Name: "-I", Values: {"foo"}
|
||||
Option 4 - Name: "<input>", Values: {"t.c"}
|
||||
</pre>
|
||||
|
||||
<p>After this stage is complete the command line should be
|
||||
broken down into well defined option objects with their
|
||||
appropriate parameters. Subsequent stages should rarely,
|
||||
if ever, need to do any string processing.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Pipeline: Compilation Job Construction</b>
|
||||
|
||||
<p>Once the arguments are parsed, the tree of subprocess
|
||||
jobs needed for the desired compilation sequence are
|
||||
constructed. This involves determing the input files and
|
||||
their types, what work is to be done on them (preprocess,
|
||||
compile, assemble, link, etc.), and constructing a list of
|
||||
Action instances for each task. The result is a list of
|
||||
one or more top-level actions, each of which generally
|
||||
corresponds to a single output (for example, an object or
|
||||
linked executable).</p>
|
||||
|
||||
<p>The majority of Actions correspond to actual tasks,
|
||||
however there are two special Actions. The first is
|
||||
InputAction, which simply serves to adapt an input
|
||||
argument for use as an input to other Actions. The second
|
||||
is BindArchAction, which conceptually alters the
|
||||
architecture to be used for all of its input Actions.</p>
|
||||
|
||||
<p>The clang driver can dump the results of this
|
||||
stage using the <tt>-ccc-print-phases</tt> flag. For
|
||||
example:</p>
|
||||
<pre>
|
||||
$ <b>clang -ccc-print-phases -x c t.c -x assembler t.s</b>
|
||||
0: input, "t.c", c
|
||||
1: preprocessor, {0}, cpp-output
|
||||
2: compiler, {1}, assembler
|
||||
3: assembler, {2}, object
|
||||
4: input, "t.s", assembler
|
||||
5: assembler, {4}, object
|
||||
6: linker, {3, 5}, image
|
||||
</pre>
|
||||
<p>Here the driver is constructing seven distinct actions,
|
||||
four to compile the "t.c" input into an object file, two to
|
||||
assemble the "t.s" input, and one to link them together.</p>
|
||||
|
||||
<p>A rather different compilation pipeline is shown here; in
|
||||
this example there are two top level actions to compile
|
||||
the input files into two separate object files, where each
|
||||
object file is built using <tt>lipo</tt> to merge results
|
||||
built for two separate architectures.</p>
|
||||
<pre>
|
||||
$ <b>clang -ccc-print-phases -c -arch i386 -arch x86_64 t0.c t1.c</b>
|
||||
0: input, "t0.c", c
|
||||
1: preprocessor, {0}, cpp-output
|
||||
2: compiler, {1}, assembler
|
||||
3: assembler, {2}, object
|
||||
4: bind-arch, "i386", {3}, object
|
||||
5: bind-arch, "x86_64", {3}, object
|
||||
6: lipo, {4, 5}, object
|
||||
7: input, "t1.c", c
|
||||
8: preprocessor, {7}, cpp-output
|
||||
9: compiler, {8}, assembler
|
||||
10: assembler, {9}, object
|
||||
11: bind-arch, "i386", {10}, object
|
||||
12: bind-arch, "x86_64", {10}, object
|
||||
13: lipo, {11, 12}, object
|
||||
</pre>
|
||||
|
||||
<p>After this stage is complete the compilation process is
|
||||
divided into a simple set of actions which need to be
|
||||
performed to produce intermediate or final outputs (in
|
||||
some cases, like <tt>-fsyntax-only</tt>, there is no
|
||||
"real" final output). Phases are well known compilation
|
||||
steps, such as "preprocess", "compile", "assemble",
|
||||
"link", etc.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Bind: Tool & Filename Selection</b>
|
||||
|
||||
<p>This stage (in conjunction with the Translate stage)
|
||||
turns the tree of Actions into a list of actual subprocess
|
||||
to run. Conceptually, the driver performs a top down
|
||||
matching to assign Action(s) to Tools. The ToolChain is
|
||||
responsible for selecting the tool to perform a particular
|
||||
action; once seleected the driver interacts with the tool
|
||||
to see if it can match additional actions (for example, by
|
||||
having an integrated preprocessor).
|
||||
|
||||
<p>Once Tools have been selected for all actions, the driver
|
||||
determines how the tools should be connected (for example,
|
||||
using an inprocess module, pipes, temporary files, or user
|
||||
provided filenames). If an output file is required, the
|
||||
driver also computes the appropriate file name (the suffix
|
||||
and file location depend on the input types and options
|
||||
such as <tt>-save-temps</tt>).
|
||||
|
||||
<p>The driver interacts with a ToolChain to perform the Tool
|
||||
bindings. Each ToolChain contains information about all
|
||||
the tools needed for compilation for a particular
|
||||
architecture, platform, and operating system. A single
|
||||
driver invocation may query multiple ToolChains during one
|
||||
compilation in order to interact with tools for separate
|
||||
architectures.</p>
|
||||
|
||||
<p>The results of this stage are not computed directly, but
|
||||
the driver can print the results via
|
||||
the <tt>-ccc-print-bindings</tt> option. For example:</p>
|
||||
<pre>
|
||||
$ <b>clang -ccc-print-bindings -arch i386 -arch ppc t0.c</b>
|
||||
# "i386-apple-darwin9" - "clang", inputs: ["t0.c"], output: "/tmp/cc-Sn4RKF.s"
|
||||
# "i386-apple-darwin9" - "darwin::Assemble", inputs: ["/tmp/cc-Sn4RKF.s"], output: "/tmp/cc-gvSnbS.o"
|
||||
# "i386-apple-darwin9" - "darwin::Link", inputs: ["/tmp/cc-gvSnbS.o"], output: "/tmp/cc-jgHQxi.out"
|
||||
# "ppc-apple-darwin9" - "gcc::Compile", inputs: ["t0.c"], output: "/tmp/cc-Q0bTox.s"
|
||||
# "ppc-apple-darwin9" - "gcc::Assemble", inputs: ["/tmp/cc-Q0bTox.s"], output: "/tmp/cc-WCdicw.o"
|
||||
# "ppc-apple-darwin9" - "gcc::Link", inputs: ["/tmp/cc-WCdicw.o"], output: "/tmp/cc-HHBEBh.out"
|
||||
# "i386-apple-darwin9" - "darwin::Lipo", inputs: ["/tmp/cc-jgHQxi.out", "/tmp/cc-HHBEBh.out"], output: "a.out"
|
||||
</pre>
|
||||
|
||||
<p>This shows the tool chain, tool, inputs and outputs which
|
||||
have been bound for this compilation sequence. Here clang
|
||||
is being used to compile t0.c on the i386 architecture and
|
||||
darwin specific versions of the tools are being used to
|
||||
assemble and link the result, but generic gcc versions of
|
||||
the tools are being used on PowerPC.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Translate: Tool Specific Argument Translation</b>
|
||||
|
||||
<p>Once a Tool has been selected to perform a particular
|
||||
Action, the Tool must construct concrete Jobs which will be
|
||||
executed during compilation. The main work is in translating
|
||||
from the gcc style command line options to whatever options
|
||||
the subprocess expects.</p>
|
||||
|
||||
<p>Some tools, such as the assembler, only interact with a
|
||||
handful of arguments and just determine the path of the
|
||||
executable to call and pass on their input and output
|
||||
arguments. Others, like the compiler or the linker, may
|
||||
translate a large number of arguments in addition.</p>
|
||||
|
||||
<p>The ArgList class provides a number of simple helper
|
||||
methods to assist with translating arguments; for example,
|
||||
to pass on only the last of arguments corresponding to some
|
||||
option, or all arguments for an option.</p>
|
||||
|
||||
<p>The result of this stage is a list of Jobs (executable
|
||||
paths and argument strings) to execute.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Execute</b>
|
||||
<p>Finally, the compilation pipeline is executed. This is
|
||||
mostly straightforward, although there is some interaction
|
||||
with options
|
||||
like <tt>-pipe</tt>, <tt>-pass-exit-codes</tt>
|
||||
and <tt>-time</tt>.</p>
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_notes">Additional Notes</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<h4 id="int_compilation">The Compilation Object</h4>
|
||||
|
||||
<p>The driver constructs a Compilation object for each set of
|
||||
command line arguments. The Driver itself is intended to be
|
||||
invariant during construct of a Compilation; an IDE should be
|
||||
able to construct a single long lived driver instance to use
|
||||
for an entire build, for example.</p>
|
||||
|
||||
<p>The Compilation object holds information that is particular
|
||||
to each compilation sequence. For example, the list of used
|
||||
temporary files (which must be removed once compilation is
|
||||
finished) and result files (which should be removed if
|
||||
compilation files).</p>
|
||||
|
||||
<h4 id="int_unified_parsing">Unified Parsing & Pipelining</h4>
|
||||
|
||||
<p>Parsing and pipeling both occur without reference to a
|
||||
Compilation instance. This is by design; the driver expects that
|
||||
both of these phases are platform neutral, with a few very well
|
||||
defined exceptions such as whether the platform uses a driver
|
||||
driver.</p>
|
||||
|
||||
<h4 id="int_toolchain_translation">ToolChain Argument Translation</h4>
|
||||
|
||||
<p>In order to match gcc very closely, the clang driver
|
||||
currently allows tool chains to perform their own translation of
|
||||
the argument list (into a new ArgList data structure). Although
|
||||
this allows the clang driver to match gcc easily, it also makes
|
||||
the driver operation much harder to understand (since the Tools
|
||||
stop seeing some arguments the user provided, and see new ones
|
||||
instead).</p>
|
||||
|
||||
<p>For example, on Darwin <tt>-gfull</tt> gets translated into
|
||||
two separate arguments, <tt>-g</tt>
|
||||
and <tt>-fno-eliminate-unused-debug-symbols</tt>. Trying to
|
||||
write Tool logic to do something with <tt>-gfull</tt> will not
|
||||
work, because at Tools run after the arguments have been
|
||||
translated.</p>
|
||||
|
||||
<p>A long term goal is to remove this tool chain specific
|
||||
translation, and instead force each tool to change its own logic
|
||||
to do the right thing on the untranslated original arguments.</p>
|
||||
|
||||
<h4 id="int_unused_warnings">Unused Argument Warnings</h4>
|
||||
<p>The driver operates by parsing all arguments but giving Tools
|
||||
the opportunity to choose which arguments to pass on. One
|
||||
downside of this infrastructure is that if the user misspells
|
||||
some option, or is confused about which options to use, some
|
||||
command line arguments the user really cared about may go
|
||||
unused. This problem is particularly important when using
|
||||
clang as a compiler, since the clang compiler does not support
|
||||
anywhere near all the options that gcc does, and we want to make
|
||||
sure users know which ones are being used.</p>
|
||||
|
||||
<p>To support this, the driver maintains a bit associated with
|
||||
each argument of whether it has been used (at all) during the
|
||||
compilation. This bit usually doesn't need to be set by hand,
|
||||
as the key ArgList accessors will set it automatically.</p>
|
||||
|
||||
<p>When a compilation is successful (there are no errors), the
|
||||
driver checks the bit and emits an "unused argument" warning for
|
||||
any arguments which were never accessed. This is conservative
|
||||
(the argument may not have been used to do what the user wanted)
|
||||
but still catches the most obvious cases.</p>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_gcc_concepts">Relation to GCC Driver Concepts</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>For those familiar with the gcc driver, this section provides
|
||||
a brief overview of how things from the gcc driver map to the
|
||||
clang driver.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>Driver Driver</b>
|
||||
<p>The driver driver is fully integrated into the clang
|
||||
driver. The driver simply constructs additional Actions to
|
||||
bind the architecture during the <i>Pipeline</i>
|
||||
phase. The tool chain specific argument translation is
|
||||
responsible for handling <tt>-Xarch_</tt>.</p>
|
||||
|
||||
<p>The one caveat is that this approach
|
||||
requires <tt>-Xarch_</tt> not be used to alter the
|
||||
compilation itself (for example, one cannot
|
||||
provide <tt>-S</tt> as an <tt>-Xarch_</tt> argument). The
|
||||
driver attempts to reject such invocations, and overall
|
||||
there isn't a good reason to abuse <tt>-Xarch_</tt> to
|
||||
that end in practice.</p>
|
||||
|
||||
<p>The upside is that the clang driver is more efficient and
|
||||
does little extra work to support universal builds. It also
|
||||
provides better error reporting and UI consistency.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Specs</b>
|
||||
<p>The clang driver has no direct correspondant for
|
||||
"specs". The majority of the functionality that is
|
||||
embedded in specs is in the Tool specific argument
|
||||
translation routines. The parts of specs which control the
|
||||
compilation pipeline are generally part of
|
||||
the <ii>Pipeline</ii> stage.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Toolchains</b>
|
||||
<p>The gcc driver has no direct understanding of tool
|
||||
chains. Each gcc binary roughly corresponds to the
|
||||
information which is embedded inside a single
|
||||
ToolChain.</p>
|
||||
|
||||
<p>The clang driver is intended to be portable and support
|
||||
complex compilation environments. All platform and tool
|
||||
chain specific code should be protected behind either
|
||||
abstract or well defined interfaces (such as whether the
|
||||
platform supports use as a driver driver).</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
1676
docs/InternalsManual.html
Normal file
1676
docs/InternalsManual.html
Normal file
File diff suppressed because it is too large
Load Diff
327
docs/LanguageExtensions.html
Normal file
327
docs/LanguageExtensions.html
Normal file
@ -0,0 +1,327 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang Language Extensions</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Clang Language Extensions</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#builtinmacros">Builtin Macros</a></li>
|
||||
<li><a href="#vectors">Vectors and Extended Vectors</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>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#targetspecific">Target-Specific Extensions</a>
|
||||
<ul>
|
||||
<li><a href="#x86-specific">X86/X86-64 Language Extensions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a>
|
||||
<ul>
|
||||
<li><a href="#analyzerattributes">Analyzer Attributes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This document describes the language extensions provided by Clang. In
|
||||
addition to the langauge extensions listed here, Clang aims to support a broad
|
||||
range of GCC extensions. Please see the <a
|
||||
href="http://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html">GCC manual</a> for
|
||||
more information on these extensions.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="builtinmacros">Builtin Macros</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>__BASE_FILE__, __INCLUDE_LEVEL__, __TIMESTAMP__, __COUNTER__</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="vectors">Vectors and Extended Vectors</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Supports the GCC vector extensions, plus some stuff like V[1]. ext_vector
|
||||
with V.xyzw syntax and other tidbits. See also <a
|
||||
href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="blocks">Blocks</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The syntax and high level language feature description is in <a
|
||||
href="BlockLanguageSpec.txt">BlockLanguageSpec.txt</a>. Implementation and ABI
|
||||
details for the clang implementation are in <a
|
||||
href="BlockImplementation.txt">BlockImplementation.txt</a>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="overloading-in-c">Function Overloading in C</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang provides support for C++ function overloading in C. Function
|
||||
overloading in C is introduced using the <tt>overloadable</tt> attribute. For
|
||||
example, one might provide several overloaded versions of a <tt>tgsin</tt>
|
||||
function that invokes the appropriate standard function computing the sine of a
|
||||
value with <tt>float</tt>, <tt>double</tt>, or <tt>long double</tt>
|
||||
precision:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#include <math.h>
|
||||
float <b>__attribute__((overloadable))</b> tgsin(float x) { return sinf(x); }
|
||||
double <b>__attribute__((overloadable))</b> tgsin(double x) { return sin(x); }
|
||||
long double <b>__attribute__((overloadable))</b> tgsin(long double x) { return sinl(x); }
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Given these declarations, one can call <tt>tgsin</tt> with a
|
||||
<tt>float</tt> value to receive a <tt>float</tt> result, with a
|
||||
<tt>double</tt> to receive a <tt>double</tt> result, etc. Function
|
||||
overloading in C follows the rules of C++ function overloading to pick
|
||||
the best overload given the call arguments, with a few C-specific
|
||||
semantics:</p>
|
||||
<ul>
|
||||
<li>Conversion from <tt>float</tt> or <tt>double</tt> to <tt>long
|
||||
double</tt> is ranked as a floating-point promotion (per C99) rather
|
||||
than as a floating-point conversion (as in C++).</li>
|
||||
|
||||
<li>A conversion from a pointer of type <tt>T*</tt> to a pointer of type
|
||||
<tt>U*</tt> is considered a pointer conversion (with conversion
|
||||
rank) if <tt>T</tt> and <tt>U</tt> are compatible types.</li>
|
||||
|
||||
<li>A conversion from type <tt>T</tt> to a value of type <tt>U</tt>
|
||||
is permitted if <tt>T</tt> and <tt>U</tt> are compatible types. This
|
||||
conversion is given "conversion" rank.</li>
|
||||
</ul>
|
||||
|
||||
<p>The declaration of <tt>overloadable</tt> functions is restricted to
|
||||
function declarations and definitions. Most importantly, if any
|
||||
function with a given name is given the <tt>overloadable</tt>
|
||||
attribute, then all function declarations and definitions with that
|
||||
name (and in that scope) must have the <tt>overloadable</tt>
|
||||
attribute. This rule even applies to redeclarations of functions whose original
|
||||
declaration had the <tt>overloadable</tt> attribute, e.g.,</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
int f(int) __attribute__((overloadable));
|
||||
float f(float); <i>// error: declaration of "f" must have the "overloadable" attribute</i>
|
||||
|
||||
int g(int) __attribute__((overloadable));
|
||||
int g(int) { } <i>// error: redeclaration of "g" must also have the "overloadable" attribute</i>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Functions marked <tt>overloadable</tt> must have
|
||||
prototypes. Therefore, the following code is ill-formed:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
int h() __attribute__((overloadable)); <i>// error: h does not have a prototype</i>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>However, <tt>overloadable</tt> functions are allowed to use a
|
||||
ellipsis even if there are no named parameters (as is permitted in C++). This feature is particularly useful when combined with the <tt>unavailable</tt> attribute:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
void honeypot(...) __attribute__((overloadable, unavailable)); <i>// calling me is an error</i>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Functions declared with the <tt>overloadable</tt> attribute have
|
||||
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
|
||||
caveats to this use of name mangling:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>Future versions of Clang may change the name mangling of
|
||||
functions overloaded in C, so you should not depend on an specific
|
||||
mangling. To be completely safe, we strongly urge the use of
|
||||
<tt>static inline</tt> with <tt>overloadable</tt> functions.</li>
|
||||
|
||||
<li>The <tt>overloadable</tt> attribute has almost no meaning when
|
||||
used in C++, because names will already be mangled and functions are
|
||||
already overloadable. However, when an <tt>overloadable</tt>
|
||||
function occurs within an <tt>extern "C"</tt> linkage specification,
|
||||
it's name <i>will</i> be mangled in the same way as it would in
|
||||
C.</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="builtins">Builtin Functions</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang supports a number of builtin library functions with the same syntax as
|
||||
GCC, including things like <tt>__builtin_nan</tt>,
|
||||
<tt>__builtin_constant_p</tt>, <tt>__builtin_choose_expr</tt>,
|
||||
<tt>__builtin_types_compatible_p</tt>, <tt>__sync_fetch_and_add</tt>, etc. In
|
||||
addition to the GCC builtins, Clang supports a number of builtins that GCC does
|
||||
not, which are listed here.</p>
|
||||
|
||||
<p>Please note that Clang does not and will not support all of the GCC builtins
|
||||
for vector operations. Instead of using builtins, you should use the functions
|
||||
defined in target-specific header files like <tt><xmmintrin.h></tt>, which
|
||||
define portable wrappers for these. Many of the Clang versions of these
|
||||
functions are implemented directly in terms of <a href="#vectors">extended
|
||||
vector support</a> instead of builtins, in order to reduce the number of
|
||||
builtins that we need to implement.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="__builtin_shufflevector">__builtin_shufflevector</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p><tt>__builtin_shufflevector</tt> is used to expression generic vector
|
||||
permutation/shuffle/swizzle operations. This builtin is also very important for
|
||||
the implementation of various target-specific header files like
|
||||
<tt><xmmintrin.h></tt>.
|
||||
</p>
|
||||
|
||||
<p><b>Syntax:</b></p>
|
||||
|
||||
<pre>
|
||||
__builtin_shufflevector(vec1, vec2, index1, index2, ...)
|
||||
</pre>
|
||||
|
||||
<p><b>Examples:</b></p>
|
||||
|
||||
<pre>
|
||||
// Identity operation - return 4-element vector V1.
|
||||
__builtin_shufflevector(V1, V1, 0, 1, 2, 3)
|
||||
|
||||
// "Splat" element 0 of V1 into a 4-element result.
|
||||
__builtin_shufflevector(V1, V1, 0, 0, 0, 0)
|
||||
|
||||
// Reverse 4-element vector V1.
|
||||
__builtin_shufflevector(V1, V1, 3, 2, 1, 0)
|
||||
|
||||
// Concatenate every other element of 4-element vectors V1 and V2.
|
||||
__builtin_shufflevector(V1, V2, 0, 2, 4, 6)
|
||||
|
||||
// Concatenate every other element of 8-element vectors V1 and V2.
|
||||
__builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
|
||||
</pre>
|
||||
|
||||
<p><b>Description:</b></p>
|
||||
|
||||
<p>The first two arguments to __builtin_shufflevector are vectors that have the
|
||||
same element type. The remaining arguments are a list of integers that specify
|
||||
the elements indices of the first two vectors that should be extracted and
|
||||
returned in a new vector. These element indices are numbered sequentially
|
||||
starting with the first vector, continuing into the second vector. Thus, if
|
||||
vec1 is a 4-element vector, index 5 would refer to the second element of vec2.
|
||||
</p>
|
||||
|
||||
<p>The result of __builtin_shufflevector is a vector
|
||||
with the same element type as vec1/vec2 but that has an element count equal to
|
||||
the number of indices specified.
|
||||
</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="targetspecific">Target-Specific Extensions</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang supports some language features conditionally on some targets.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="x86-specific">X86/X86-64 Language Extensions</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The X86 backend has these language extensions:</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h4 id="x86-gs-segment">Memory references off the GS segment</h4>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Annotating a pointer with address space #256 causes it to be code generated
|
||||
relative to the X86 GS segment register, and address space #257 causes it to be
|
||||
relative to the X86 FS segment. Note that this is a very very low-level
|
||||
feature that should only be used if you know what you're doing (for example in
|
||||
an OS kernel).</p>
|
||||
|
||||
<p>Here is an example:</p>
|
||||
|
||||
<pre>
|
||||
#define GS_RELATIVE __attribute__((address_space(256)))
|
||||
int foo(int GS_RELATIVE *P) {
|
||||
return *P;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>Which compiles to (on X86-32):</p>
|
||||
|
||||
<pre>
|
||||
_foo:
|
||||
movl 4(%esp), %eax
|
||||
movl %gs:(%eax), %eax
|
||||
ret
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="analyzerspecific">Static Analysis-Specific Extensions</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang supports additional attributes that are useful for documenting program
|
||||
invariants and rules for static analysis tools. The extensions documented here
|
||||
are used by the <a
|
||||
href="http://clang.llvm.org/StaticAnalysis.html">path-sensitive static analyzer
|
||||
engine</a> that is part of Clang's Analysis library.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="analyzerattributes">Analyzer Attributes</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<h4 id="attr_analyzer_noreturn"><tt>analyzer_noreturn</tt></h4>
|
||||
|
||||
<p>Clang's static analysis engine understands the standard <tt>noreturn</tt>
|
||||
attribute. This attribute, which is typically affixed to a function prototype,
|
||||
indicates that a call to a given function never returns. Function prototypes for
|
||||
common functions like <tt>exit</tt> are typically annotated with this attribute,
|
||||
as well as a variety of common assertion handlers. Users can educate the static
|
||||
analyzer about their own custom assertion handles (thus cutting down on false
|
||||
positives due to false paths) by marking their own "panic" functions
|
||||
with this attribute.</p>
|
||||
|
||||
<p>While useful, <tt>noreturn</tt> is not applicable in all cases. Sometimes
|
||||
there are special functions that for all intensive purposes should be considered
|
||||
panic functions (i.e., they are only called when an internal program error
|
||||
occurs) but may actually return so that the program can fail gracefully. The
|
||||
<tt>analyzer_noreturn</tt> attribute allows one to annotate such functions as
|
||||
being interpreted as "no return" functions by the analyzer (thus
|
||||
pruning bogus paths) but will not affect compilation (as in the case of
|
||||
<tt>noreturn</tt>).</p>
|
||||
|
||||
<p><b>Usage</b>: The <tt>analyzer_noreturn</tt> attribute can be placed in the
|
||||
same places where the <tt>noreturn</tt> attribute can be placed. It is commonly
|
||||
placed at the end of function prototypes:</p>
|
||||
|
||||
<pre>
|
||||
void foo() <b>__attribute__((analyzer_noreturn))</b>;
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
97
docs/Makefile
Normal file
97
docs/Makefile
Normal file
@ -0,0 +1,97 @@
|
||||
##===- docs/Makefile ---------------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL := ../../..
|
||||
DIRS := tools
|
||||
|
||||
ifdef BUILD_FOR_WEBSITE
|
||||
PROJ_OBJ_DIR = .
|
||||
DOXYGEN = doxygen
|
||||
|
||||
$(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
|
||||
cat $< | sed \
|
||||
-e 's/@abs_top_srcdir@/../g' \
|
||||
-e 's/@DOT@/dot/g' \
|
||||
-e 's/@PACKAGE_VERSION@/mainline/' \
|
||||
-e 's/@abs_top_builddir@/../g' > $@
|
||||
endif
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
HTML := $(wildcard $(PROJ_SRC_DIR)/*.html) \
|
||||
$(wildcard $(PROJ_SRC_DIR)/*.css)
|
||||
#IMAGES := $(wildcard $(PROJ_SRC_DIR)/img/*.*)
|
||||
DOXYFILES := doxygen.cfg.in doxygen.css doxygen.footer doxygen.header \
|
||||
doxygen.intro
|
||||
EXTRA_DIST := $(HTML) $(DOXYFILES) llvm.css CommandGuide img
|
||||
|
||||
.PHONY: install-html install-doxygen doxygen generated
|
||||
|
||||
install_targets :=
|
||||
ifndef ONLY_MAN_DOCS
|
||||
install_targets += install-html
|
||||
endif
|
||||
ifeq ($(ENABLE_DOXYGEN),1)
|
||||
install_targets += install-doxygen
|
||||
endif
|
||||
install-local:: $(install_targets)
|
||||
|
||||
# Live documentation is generated for the web site using this target:
|
||||
# 'make generated BUILD_FOR_WEBSITE=1'
|
||||
generated:: doxygen
|
||||
|
||||
install-html: $(PROJ_OBJ_DIR)/html.tar.gz
|
||||
$(Echo) Installing HTML documentation
|
||||
$(Verb) $(MKDIR) $(PROJ_docsdir)/html
|
||||
$(Verb) $(MKDIR) $(PROJ_docsdir)/html/img
|
||||
$(Verb) $(DataInstall) $(HTML) $(PROJ_docsdir)/html
|
||||
# $(Verb) $(DataInstall) $(IMAGES) $(PROJ_docsdir)/html/img
|
||||
$(Verb) $(DataInstall) $(PROJ_OBJ_DIR)/html.tar.gz $(PROJ_docsdir)
|
||||
|
||||
$(PROJ_OBJ_DIR)/html.tar.gz: $(HTML)
|
||||
$(Echo) Packaging HTML documentation
|
||||
$(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
|
||||
|
||||
install-doxygen: doxygen
|
||||
$(Echo) Installing doxygen documentation
|
||||
$(Verb) $(MKDIR) $(PROJ_docsdir)/html/doxygen
|
||||
$(Verb) $(DataInstall) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(PROJ_docsdir)
|
||||
$(Verb) cd $(PROJ_OBJ_DIR)/doxygen && \
|
||||
$(FIND) . -type f -exec \
|
||||
$(DataInstall) {} $(PROJ_docsdir)/html/doxygen \;
|
||||
|
||||
doxygen: regendoc $(PROJ_OBJ_DIR)/doxygen.tar.gz
|
||||
|
||||
regendoc:
|
||||
$(Echo) Building doxygen documentation
|
||||
$(Verb) if test -e $(PROJ_OBJ_DIR)/doxygen ; then \
|
||||
$(RM) -rf $(PROJ_OBJ_DIR)/doxygen ; \
|
||||
fi
|
||||
$(Verb) $(DOXYGEN) $(PROJ_OBJ_DIR)/doxygen.cfg
|
||||
|
||||
$(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) $(CP) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(PROJ_OBJ_DIR)/doxygen/html/
|
||||
|
||||
userloc: $(LLVM_SRC_ROOT)/docs/userloc.html
|
||||
|
||||
$(LLVM_SRC_ROOT)/docs/userloc.html:
|
||||
$(Echo) Making User LOC Table
|
||||
$(Verb) cd $(LLVM_SRC_ROOT) ; ./utils/userloc.pl -details -recurse \
|
||||
-html lib include tools runtime utils examples autoconf test > docs/userloc.html
|
||||
|
||||
uninstall-local::
|
||||
$(Echo) Uninstalling Documentation
|
||||
$(Verb) $(RM) -rf $(PROJ_docsdir)
|
71
docs/PCHInternals.html
Normal file
71
docs/PCHInternals.html
Normal file
@ -0,0 +1,71 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||
<html> <head>
|
||||
<title>Precompiled Headers (PCH)</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Precompiled Headers</h1>
|
||||
|
||||
<p>This document describes the design and implementation of Clang's
|
||||
precompiled headers (PCH). If you are interested in the end-user
|
||||
view, please see the <a
|
||||
href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
|
||||
|
||||
<h2>Using precompiled headers with <tt>clang-cc</tt></h2>
|
||||
|
||||
<p>The low-level Clang compiler, <tt>clang-cc</tt>, supports two command
|
||||
line options for generating and using PCH files.<p>
|
||||
|
||||
<p>To generate PCH files using <tt>clang-cc</tt>, use the option
|
||||
<b><tt>-emit-pch</tt></b>:
|
||||
|
||||
<pre> $ clang-cc test.h -emit-pch -o test.h.pch </pre>
|
||||
|
||||
<p>This option is transparently used by <tt>clang</tt> when generating
|
||||
PCH files. The resulting PCH file contains the serialized form of the
|
||||
compiler's internal representation after it has completed parsing and
|
||||
semantic analysis. The PCH file can then be used as a prefix header
|
||||
with the <b><tt>-include-pch</tt></b> option:</p>
|
||||
|
||||
<pre>
|
||||
$ clang-cc -include-pch test.h.pch test.c -o test.s
|
||||
</pre>
|
||||
|
||||
<h2>PCH Design Philosophy</h2>
|
||||
|
||||
<p>Precompiled headers are meant to improve overall compile times for
|
||||
projects, so the design of precompiled headers is entirely driven by
|
||||
performance concerns. The use case for precompiled headers is
|
||||
relatively simple: when there is a common set of headers that is
|
||||
included in nearly every source file in the project, we
|
||||
<i>precompile</i> that bundle of headers into a single precompiled
|
||||
header (PCH file). Then, when compiling the source files in the
|
||||
project, we load the PCH file first (as a prefix header), which acts
|
||||
as a stand-in for that bundle of headers.</p>
|
||||
|
||||
<p>A precompiled header implementation improves performance when:</p>
|
||||
<ul>
|
||||
<li>Loading the PCH file is significantly faster than re-parsing the
|
||||
bundle of headers stored within the PCH file. Thus, a precompiled
|
||||
header design attempts to minimize the cost of reading the PCH
|
||||
file. Ideally, this cost should not vary with the size of the
|
||||
precompiled header file.</li>
|
||||
|
||||
<li>The cost of generating the PCH file initially is not so large
|
||||
that it counters the per-source-file performance improvement due to
|
||||
eliminating the need to parse the bundled headers in the first
|
||||
place. This is particularly important on multi-core systems, because
|
||||
PCH file generation serializes the build when all compilations
|
||||
require the PCH file to be up-to-date.</li>
|
||||
</ul>
|
||||
|
||||
<p>More to be written...</p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
177
docs/PTHInternals.html
Normal file
177
docs/PTHInternals.html
Normal file
@ -0,0 +1,177 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Pretokenized Headers (PTH)</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Pretokenized Headers (PTH)</h1>
|
||||
|
||||
<p>This document first describes the low-level
|
||||
interface for using PTH and then briefly elaborates on its design and
|
||||
implementation. If you are interested in the end-user view, please see the
|
||||
<a href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
|
||||
|
||||
|
||||
<h2>Using Pretokenized Headers with <tt>clang-cc</tt> (Low-level Interface)</h2>
|
||||
|
||||
<p>The low-level Clang compiler tool, <tt>clang-cc</tt>, supports three command
|
||||
line options for generating and using PTH files.<p>
|
||||
|
||||
<p>To generate PTH files using <tt>clang-cc</tt>, use the option
|
||||
<b><tt>-emit-pth</tt></b>:
|
||||
|
||||
<pre> $ clang-cc test.h -emit-pth -o test.h.pth </pre>
|
||||
|
||||
<p>This option is transparently used by <tt>clang</tt> when generating PTH
|
||||
files. Similarly, PTH files can be used as prefix headers using the
|
||||
<b><tt>-include-pth</tt></b> option:</p>
|
||||
|
||||
<pre>
|
||||
$ clang-cc -include-pth test.h.pth test.c -o test.s
|
||||
</pre>
|
||||
|
||||
<p>Alternatively, Clang's PTH files can be used as a raw "token-cache"
|
||||
(or "content" cache) of the source included by the original header
|
||||
file. This means that the contents of the PTH file are searched as substitutes
|
||||
for <em>any</em> source files that are used by <tt>clang-cc</tt> to process a
|
||||
source file. This is done by specifying the <b><tt>-token-cache</tt></b>
|
||||
option:</p>
|
||||
|
||||
<pre>
|
||||
$ cat test.h
|
||||
#include <stdio.h>
|
||||
$ clang-cc -emit-pth test.h -o test.h.pth
|
||||
$ cat test.c
|
||||
#include "test.h"
|
||||
$ clang-cc test.c -o test -token-cache test.h.pth
|
||||
</pre>
|
||||
|
||||
<p>In this example the contents of <tt>stdio.h</tt> (and the files it includes)
|
||||
will be retrieved from <tt>test.h.pth</tt>, as the PTH file is being used in
|
||||
this case as a raw cache of the contents of <tt>test.h</tt>. This is a low-level
|
||||
interface used to both implement the high-level PTH interface as well as to
|
||||
provide alternative means to use PTH-style caching.</p>
|
||||
|
||||
<h2>PTH Design and Implementation</h2>
|
||||
|
||||
<p>Unlike GCC's precompiled headers, which cache the full ASTs and preprocessor
|
||||
state of a header file, Clang's pretokenized header files mainly cache the raw
|
||||
lexer <em>tokens</em> that are needed to segment the stream of characters in a
|
||||
source file into keywords, identifiers, and operators. Consequently, PTH serves
|
||||
to mainly directly speed up the lexing and preprocessing of a source file, while
|
||||
parsing and type-checking must be completely redone every time a PTH file is
|
||||
used.</p>
|
||||
|
||||
<h3>Basic Design Tradeoffs</h3>
|
||||
|
||||
<p>In the long term there are plans to provide an alternate PCH implementation
|
||||
for Clang that also caches the work for parsing and type checking the contents
|
||||
of header files. The current implementation of PCH in Clang as pretokenized
|
||||
header files was motivated by the following factors:<p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><p><b>Language independence</b>: PTH files work with any language that
|
||||
Clang's lexer can handle, including C, Objective-C, and (in the early stages)
|
||||
C++. This means development on language features at the parsing level or above
|
||||
(which is basically almost all interesting pieces) does not require PTH to be
|
||||
modified.</p></li>
|
||||
|
||||
<li><b>Simple design</b>: Relatively speaking, PTH has a simple design and
|
||||
implementation, making it easy to test. Further, because the machinery for PTH
|
||||
resides at the lower-levels of the Clang library stack it is fairly
|
||||
straightforward to profile and optimize.</li>
|
||||
</ul>
|
||||
|
||||
<p>Further, compared to GCC's PCH implementation (which is the dominate
|
||||
precompiled header file implementation that Clang can be directly compared
|
||||
against) the PTH design in Clang yields several attractive features:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><p><b>Architecture independence</b>: In contrast to GCC's PCH files (and
|
||||
those of several other compilers), Clang's PTH files are architecture
|
||||
independent, requiring only a single PTH file when building an program for
|
||||
multiple architectures.</p>
|
||||
|
||||
<p>For example, on Mac OS X one may wish to
|
||||
compile a "universal binary" that runs on PowerPC, 32-bit Intel
|
||||
(i386), and 64-bit Intel architectures. In contrast, GCC requires a PCH file for
|
||||
each architecture, as the definitions of types in the AST are
|
||||
architecture-specific. Since a Clang PTH file essentially represents a lexical
|
||||
cache of header files, a single PTH file can be safely used when compiling for
|
||||
multiple architectures. This can also reduce compile times because only a single
|
||||
PTH file needs to be generated during a build instead of several.</p></li>
|
||||
|
||||
<li><p><b>Reduced memory pressure</b>: Similar to GCC,
|
||||
Clang reads PTH files via the use of memory mapping (i.e., <tt>mmap</tt>).
|
||||
Clang, however, memory maps PTH files as read-only, meaning that multiple
|
||||
invocations of <tt>clang-cc</tt> can share the same pages in memory from a
|
||||
memory-mapped PTH file. In comparison, GCC also memory maps its PCH files but
|
||||
also modifies those pages in memory, incurring the copy-on-write costs. The
|
||||
read-only nature of PTH can greatly reduce memory pressure for builds involving
|
||||
multiple cores, thus improving overall scalability.</p></li>
|
||||
|
||||
<li><p><b>Fast generation</b>: PTH files can be generated in a small fraction
|
||||
of the time needed to generate GCC's PCH files. Since PTH/PCH generation is a
|
||||
serial operation that typically blocks progress during a build, faster
|
||||
generation time leads to improved processor utilization with parallel builds on
|
||||
multicore machines.</p></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>Despite these strengths, PTH's simple design suffers some algorithmic
|
||||
handicaps compared to other PCH strategies such as those used by GCC. While PTH
|
||||
can greatly speed up the processing time of a header file, the amount of work
|
||||
required to process a header file is still roughly linear in the size of the
|
||||
header file. In contrast, the amount of work done by GCC to process a
|
||||
precompiled header is (theoretically) constant (the ASTs for the header are
|
||||
literally memory mapped into the compiler). This means that only the pieces of
|
||||
the header file that are referenced by the source file including the header are
|
||||
the only ones the compiler needs to process during actual compilation. While
|
||||
GCC's particular implementation of PCH mitigates some of these algorithmic
|
||||
strengths via the use of copy-on-write pages, the approach itself can
|
||||
fundamentally dominate at an algorithmic level, especially when one considers
|
||||
header files of arbitrary size.</p>
|
||||
|
||||
<p>There are plans to potentially implement an complementary PCH implementation
|
||||
for Clang based on the lazy deserialization of ASTs. This approach would
|
||||
theoretically have the same constant-time algorithmic advantages just mentioned
|
||||
but would also retain some of the strengths of PTH such as reduced memory
|
||||
pressure (ideal for multi-core builds).</p>
|
||||
|
||||
<h3>Internal PTH Optimizations</h3>
|
||||
|
||||
<p>While the main optimization employed by PTH is to reduce lexing time of
|
||||
header files by caching pre-lexed tokens, PTH also employs several other
|
||||
optimizations to speed up the processing of header files:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><p><em><tt>stat</tt> caching</em>: PTH files cache information obtained via
|
||||
calls to <tt>stat</tt> that <tt>clang-cc</tt> uses to resolve which files are
|
||||
included by <tt>#include</tt> directives. This greatly reduces the overhead
|
||||
involved in context-switching to the kernel to resolve included files.</p></li>
|
||||
|
||||
<li><p><em>Fasting skipping of <tt>#ifdef</tt>...<tt>#endif</tt> chains</em>:
|
||||
PTH files record the basic structure of nested preprocessor blocks. When the
|
||||
condition of the preprocessor block is false, all of its tokens are immediately
|
||||
skipped instead of requiring them to be handled by Clang's
|
||||
preprocessor.</p></li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
688
docs/UsersManual.html
Normal file
688
docs/UsersManual.html
Normal file
@ -0,0 +1,688 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang Compiler User's Manual</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Clang Compiler User's Manual</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a>
|
||||
<ul>
|
||||
<li><a href="#terminology">Terminology</a></li>
|
||||
<li><a href="#basicusage">Basic Usage</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#commandline">Command Line Options</a>
|
||||
<ul>
|
||||
<li><a href="#cl_diagnostics">Options to Control Error and Warning
|
||||
Messages</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#general_features">Language and Target-Independent Features</a>
|
||||
<ul>
|
||||
<li><a href="#diagnostics">Controlling Errors and Warnings</a></li>
|
||||
<li><a href="#precompiledheaders">Precompiled Headers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#c">C Language Features</a>
|
||||
<ul>
|
||||
<li><a href="#c_ext">Extensions supported by clang</a></li>
|
||||
<li><a href="#c_modes">Differences between various standard modes</a></li>
|
||||
<li><a href="#c_unimpl_gcc">GCC extensions not implemented yet</a></li>
|
||||
<li><a href="#c_unsupp_gcc">Intentionally unsupported GCC extensions</a></li>
|
||||
<li><a href="#c_ms">Microsoft extensions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#objc">Objective-C Language Features</a>
|
||||
<ul>
|
||||
<li><a href="#objc_incompatibilities">Intentional Incompatibilities with
|
||||
GCC</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#cxx">C++ Language Features</a>
|
||||
<ul>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#objcxx">Objective C++ Language Features</a>
|
||||
<ul>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#target_features">Target-Specific Features and Limitations</a>
|
||||
<ul>
|
||||
<li><a href="#target_arch">CPU Architectures Features and Limitations</a>
|
||||
<ul>
|
||||
<li><a href="#target_arch_x86">X86</a></li>
|
||||
<li>PPC</li>
|
||||
<li>ARM</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#target_os">Operating System Features and Limitations</a>
|
||||
<ul>
|
||||
<li><a href="#target_os_darwin">Darwin (Mac OS/X)</a></li>
|
||||
<li>Linux, etc.</li>
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The Clang Compiler is an open-source compiler for the C family of programming
|
||||
languages, aiming to be the best in class implementation of these languages.
|
||||
Clang builds on the LLVM optimizer and code generator, allowing it to provide
|
||||
high-quality optimization and code generation support for many targets. For
|
||||
more general information, please see the <a href="http://clang.llvm.org">Clang
|
||||
Web Site</a> or the <a href="http://llvm.org">LLVM Web Site</a>.</p>
|
||||
|
||||
<p>This document describes important notes about using Clang as a compiler for
|
||||
an end-user, documenting the supported features, command line options, etc. If
|
||||
you are interested in using Clang to build a tool that processes code, please
|
||||
see <a href="InternalsManual.html">the Clang Internals Manual</a>. If you are
|
||||
interested in the <a href="http://clang.llvm.org/StaticAnalysis.html">Clang
|
||||
Static Analyzer</a>, please see its web page.</p>
|
||||
|
||||
<p>Clang is designed to support the C family of programming languages, which
|
||||
includes <a href="#c">C</a>, <a href="#objc">Objective-C</a>, <a
|
||||
href="#cxx">C++</a>, and <a href="#objcxx">Objective-C++</a> as well as many
|
||||
dialects of those. For language-specific information, please see the
|
||||
corresponding language specific section:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="#c">C Language</a>: K&R C, ANSI C89, ISO C90, ISO C94
|
||||
(C89+AMD1), ISO C99 (+TC1, TC2, TC3). </li>
|
||||
<li><a href="#objc">Objective-C Language</a>: ObjC 1, ObjC 2, ObjC 2.1, plus
|
||||
variants depending on base language.</li>
|
||||
<li><a href="#cxx">C++ Language Features</a></li>
|
||||
<li><a href="#objcxx">Objective C++ Language</a></li>
|
||||
</ul>
|
||||
|
||||
<p>In addition to these base languages and their dialects, Clang supports a
|
||||
broad variety of language extensions, which are documented in the corresponding
|
||||
language section. These extensions are provided to be compatible with the GCC,
|
||||
Microsoft, and other popular compilers as well as to improve functionality
|
||||
through Clang-specific features. The Clang driver and language features are
|
||||
intentionally designed to be as compatible with the GNU GCC compiler as
|
||||
reasonably possible, easing migration from GCC to Clang. In most cases, code
|
||||
"just works".</p>
|
||||
|
||||
<p>In addition to language specific features, Clang has a variety of features
|
||||
that depend on what CPU architecture or operating system is being compiled for.
|
||||
Please see the <a href="target_features">Target-Specific Features and
|
||||
Limitations</a> section for more details.</p>
|
||||
|
||||
<p>The rest of the introduction introduces some basic <a
|
||||
href="#terminology">compiler terminology</a> that is used throughout this manual
|
||||
and contains a basic <a href="#basicusage">introduction to using Clang</a>
|
||||
as a command line compiler.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="terminology">Terminology</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>Front end, parser, backend, preprocessor, undefined behavior, diagnostic,
|
||||
optimizer</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="basicusage">Basic Usage</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>Intro to how to use a C compiler for newbies.</p>
|
||||
<p>
|
||||
compile + link
|
||||
|
||||
compile then link
|
||||
|
||||
debug info
|
||||
|
||||
enabling optimizations
|
||||
|
||||
picking a language to use, defaults to C99 by default. Autosenses based on
|
||||
extension.
|
||||
|
||||
using a makefile
|
||||
</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="commandline">Command Line Options</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>
|
||||
This section is generally an index into other sections. It does not go into
|
||||
depth on the ones that are covered by other sections. However, the first part
|
||||
introduces the language selection and other high level options like -c, -g, etc.
|
||||
</p>
|
||||
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="cl_diagnostics">Options to Control Error and Warning Messages</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p><b>-Werror</b>: Turn warnings into errors.</p>
|
||||
<p><b>-Werror=foo</b>: Turn warning "foo" into an error.</p>
|
||||
<p><b>-Wno-error=foo</b>: Turn warning "foo" into an warning even if -Werror is
|
||||
specified.</p>
|
||||
<p><b>-Wfoo</b>: Enable warning foo</p>
|
||||
<p><b>-Wno-foo</b>: Disable warning foo</p>
|
||||
<p><b>-w</b>: Disable all warnings.</p>
|
||||
<p><b>-pedantic</b>: Warn on language extensions.</p>
|
||||
<p><b>-pedantic-errors</b>: Error on language extensions.</p>
|
||||
<p><b>-Wsystem-headers</b>: Enable warnings from system headers.</p>
|
||||
|
||||
<!-- ================================================= -->
|
||||
<h4 id="cl_diag_formatting">Formatting of Diagnostics</h4>
|
||||
<!-- ================================================= -->
|
||||
|
||||
<p>Clang aims to produce beautiful diagnostics by default, particularly for new
|
||||
users that first come to Clang. However, different people have different
|
||||
preferences, and sometimes Clang is driven by another program that wants to
|
||||
parse simple and consistent output, not a person. For these cases, Clang
|
||||
provides a wide range of options to control the exact output format of the
|
||||
diagnostics that it generates.</p>
|
||||
|
||||
<dl>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fshow-column"><b>-f[no-]show-column</b>: Print column number in
|
||||
diagnostic.</dt>
|
||||
<dd>This option, which defaults to on, controls whether or not Clang prints the
|
||||
column number of a diagnostic. For example, when this is enabled, Clang will
|
||||
print something like:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
#endif bad
|
||||
^
|
||||
//
|
||||
</pre>
|
||||
|
||||
<p>When this is disabled, Clang will print "test.c:28: warning..." with no
|
||||
column number.</p>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fshow-source-location"><b>-f[no-]show-source-location</b>: Print
|
||||
source file/line/column information in diagnostic.</dt>
|
||||
<dd>This option, which defaults to on, controls whether or not Clang prints the
|
||||
filename, line number and column number of a diagnostic. For example,
|
||||
when this is enabled, Clang will print something like:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
#endif bad
|
||||
^
|
||||
//
|
||||
</pre>
|
||||
|
||||
<p>When this is disabled, Clang will not print the "test.c:28:8: " part.</p>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fcaret-diagnostics"><b>-f[no-]caret-diagnostics</b>: Print source
|
||||
line and ranges from source code in diagnostic.</dt>
|
||||
<dd>This option, which defaults to on, controls whether or not Clang prints the
|
||||
source line, source ranges, and caret when emitting a diagnostic. For example,
|
||||
when this is enabled, Clang will print something like:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
#endif bad
|
||||
^
|
||||
//
|
||||
</pre>
|
||||
|
||||
<p>When this is disabled, Clang will just print:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
</pre>
|
||||
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-show-option"><b>-f[no-]diagnostics-show-option</b>:
|
||||
Enable <tt>[-Woption]</tt> information in diagnostic line.</dt>
|
||||
<dd>This option, which defaults to on,
|
||||
controls whether or not Clang prints the associated <A
|
||||
href="#cl_diag_warning_groups">warning group</a> option name when outputting
|
||||
a warning diagnostic. For example, in this output:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
#endif bad
|
||||
^
|
||||
//
|
||||
</pre>
|
||||
|
||||
<p>Passing <b>-fno-diagnostics-show-option</b> will prevent Clang from printing
|
||||
the [<a href="#opt_Wextra-tokens">-Wextra-tokens</a>] information in the
|
||||
diagnostic. This information tells you the flag needed to enable or disable the
|
||||
diagnostic, either from the command line or through <a
|
||||
href="#pragma_GCC_diagnostic">#pragma GCC diagnostic</a>.</dd>
|
||||
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-fixit-info"><b>-f[no-]diagnostics-fixit-info</b>:
|
||||
Enable "FixIt" information in the diagnostics output.</dt>
|
||||
<dd>This option, which defaults to on, controls whether or not Clang prints the
|
||||
information on how to fix a specific diagnostic underneath it when it knows.
|
||||
For example, in this output:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
#endif bad
|
||||
^
|
||||
//
|
||||
</pre>
|
||||
|
||||
<p>Passing <b>-fno-diagnostics-fixit-info</b> will prevent Clang from printing
|
||||
the "//" line at the end of the message. This information is useful for users
|
||||
who may not understand what is wrong, but can be confusing for machine
|
||||
parsing.</p>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-print-source-range-info">
|
||||
<b>-f[no-]diagnostics-print-source-range-info</b>:
|
||||
Print machine parsable information about source ranges.</dt>
|
||||
<dd>This option, which defaults to off, controls whether or not Clang prints
|
||||
information about source ranges in a machine parsable format after the
|
||||
file/line/column number information. The information is a simple sequence of
|
||||
brace enclosed ranges, where each range lists the start and end line/column
|
||||
locations. For example, in this output:</p>
|
||||
|
||||
<pre>
|
||||
exprs.c:47:15:{47:8-47:14}{47:17-47:24}: error: invalid operands to binary expression ('int *' and '_Complex float')
|
||||
P = (P-42) + Gamma*4;
|
||||
~~~~~~ ^ ~~~~~~~
|
||||
</pre>
|
||||
|
||||
<p>The {}'s are generated by -fdiagnostics-print-source-range-info.</p>
|
||||
</dd>
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ===================================================== -->
|
||||
<h4 id="cl_diag_warning_groups">Individual Warning Groups</h4>
|
||||
<!-- ===================================================== -->
|
||||
|
||||
<p>TODO: Generate this from tblgen. Define one anchor per warning group.</p>
|
||||
|
||||
|
||||
<dl>
|
||||
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_Wextra-tokens"><b>-Wextra-tokens</b>: Warn about excess tokens at
|
||||
the end of a preprocessor directive.</dt>
|
||||
<dd>This option, which defaults to on, enables warnings about extra tokens at
|
||||
the end of preprocessor directives. For example:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
#endif bad
|
||||
^
|
||||
</pre>
|
||||
|
||||
<p>These extra tokens are not strictly conforming, and are usually best handled
|
||||
by commenting them out.</p>
|
||||
|
||||
<p>This option is also enabled by <a href="">-Wfoo</a>, <a href="">-Wbar</a>,
|
||||
and <a href="">-Wbaz</a>.</p>
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="general_features">Language and Target-Independent Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="diagnostics">Controlling Errors and Warnings</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>Clang provides a number of ways to control which code constructs cause it to
|
||||
emit errors and warning messages, and how they are displayed to the console.</p>
|
||||
|
||||
<h4>Controlling How Clang Displays Diagnostics</h4>
|
||||
|
||||
<p>When Clang emits a diagnostic, it includes rich information in the output,
|
||||
and gives you fine-grain control over which information is printed. Clang has
|
||||
the ability to print this information, and these are the options that control
|
||||
it:</p>
|
||||
|
||||
<p>
|
||||
<ol>
|
||||
<li>A file/line/column indicator that shows exactly where the diagnostic occurs
|
||||
in your code [<a href="#opt_fshow-column">-fshow-column</a>, <a
|
||||
href="#opt_fshow-source-location">-fshow-source-location</a>].</li>
|
||||
<li>A categorization of the diagnostic as a note, warning, error, or fatal
|
||||
error.</li>
|
||||
<li>A text string that describes what the problem is.</li>
|
||||
<li>An option that indicates how to control the diagnostic (for diagnostics that
|
||||
support it) [<a
|
||||
href="#opt_fdiagnostics-show-option">-fdiagnostics-show-option</a>].</li>
|
||||
<li>The line of source code that the issue occurs on, along with a caret and
|
||||
ranges that indicate the important locations [<a
|
||||
href="opt_fcaret-diagnostics">-fcaret-diagnostics</a>].</li>
|
||||
<li>"FixIt" information, which is a concise explanation of how to fix the
|
||||
problem (when Clang is certain it knows) [<a
|
||||
href="opt_fdiagnostics-fixit-info">-fdiagnostics-fixit-info</a>].</li>
|
||||
<li>A machine-parsable representation of the ranges involved (off by
|
||||
default) [<a
|
||||
href="opt_fdiagnostics-print-source-range-info">-fdiagnostics-print-source-range-info</a>].</li>
|
||||
</ol></p>
|
||||
|
||||
<p>For more information please see <a href="#cl_diag_formatting">Formatting of
|
||||
Diagnostics</a>.</p>
|
||||
|
||||
<h4>Controlling Which Diagnostics Clang Generates</h4>
|
||||
|
||||
<p>mappings: ignore, note, warning, error, fatal</p>
|
||||
|
||||
<p>
|
||||
The two major classes are control from the command line and control via pragmas
|
||||
in your code.</p>
|
||||
|
||||
|
||||
<p>-W flags, -pedantic, etc</p>
|
||||
|
||||
<p>pragma GCC diagnostic</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="precompiledheaders">Precompiled Headers</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p><a href="http://en.wikipedia.org/wiki/Precompiled_header">Precompiled
|
||||
headers</a> are a general approach employed by many compilers to reduce
|
||||
compilation time. The underlying motivation of the approach is that it is
|
||||
common for the same (and often large) header files to be included by
|
||||
multiple source files. Consequently, compile times can often be greatly improved
|
||||
by caching some of the (redundant) work done by a compiler to process headers.
|
||||
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
|
||||
highly effective at speeding up program compilation on systems with very large
|
||||
system headers (e.g., Mac OS/X).</p>
|
||||
|
||||
<p>Clang supports an implementation of precompiled headers known as
|
||||
<em>pre-tokenized headers</em> (PTH). Clang's pre-tokenized headers support most
|
||||
of same interfaces as GCC's pre-compiled headers (as well as others) but are
|
||||
completely different in their implementation. If you are interested in how
|
||||
PTH is implemented, please see the <a href="PTHInternals.html">PTH Internals
|
||||
document</a>.</p>
|
||||
|
||||
<h4>Generating a PTH File</h4>
|
||||
|
||||
<p>To generate a PTH file using Clang, one invokes Clang with
|
||||
the <b><tt>-x <i><language></i>-header</tt></b> option. This mirrors the
|
||||
interface in GCC for generating PCH files:</p>
|
||||
|
||||
<pre>
|
||||
$ gcc -x c-header test.h -o test.h.gch
|
||||
$ clang -x c-header test.h -o test.h.pth
|
||||
</pre>
|
||||
|
||||
<h4>Using a PTH File</h4>
|
||||
|
||||
<p>A PTH file can then be used as a prefix header when a
|
||||
<b><tt>-include</tt></b> option is passed to <tt>clang</tt>:</p>
|
||||
|
||||
<pre>
|
||||
$ clang -include test.h test.c -o test
|
||||
</pre>
|
||||
|
||||
<p>The <tt>clang</tt> driver will first check if a PTH file for <tt>test.h</tt>
|
||||
is available; if so, the contents of <tt>test.h</tt> (and the files it includes)
|
||||
will be processed from the PTH file. Otherwise, Clang falls back to
|
||||
directly processing the content of <tt>test.h</tt>. This mirrors the behavior of
|
||||
GCC.</p>
|
||||
|
||||
<p><b>NOTE:</b> Clang does <em>not</em> automatically use PTH files
|
||||
for headers that are directly included within a source file. For example:</p>
|
||||
|
||||
<pre>
|
||||
$ clang -x c-header test.h -o test.h.pth
|
||||
$ cat test.c
|
||||
#include "test.h"
|
||||
$ clang test.c -o test
|
||||
</pre>
|
||||
|
||||
<p>In this example, <tt>clang</tt> will not automatically use the PTH file for
|
||||
<tt>test.h</tt> since <tt>test.h</tt> was included directly in the source file
|
||||
and not specified on the command line using <tt>-include</tt>.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="c">C Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The support for standard C in clang is feature-complete except for the C99
|
||||
floating-point pragmas.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="c_ext">Extensions supported by clang</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>See <a href="LanguageExtensions.html">clang language extensions</a>.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="c_modes">Differences between various standard modes</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>clang supports the -std option, which changes what language mode clang uses.
|
||||
The supported modes for C are c89, gnu89, c94, c99, gnu99 and various aliases
|
||||
for those modes. If no -std option is specified, clang defaults to gnu99 mode.
|
||||
</p>
|
||||
|
||||
<p>Differences between all c* and gnu* modes:</p>
|
||||
<ul>
|
||||
<li>c* modes define "__STRICT_ANSI__".</li>
|
||||
<li>Target-specific defines not prefixed by underscores, like "linux", are
|
||||
defined in gnu* modes.</li>
|
||||
<li>Trigraphs default to being off in gnu* modes; they can be enabled by the
|
||||
-trigraphs option.</li>
|
||||
<li>The parser recognizes "asm" and "typeof" as keywords in gnu* modes; the
|
||||
variants "__asm__" and "__typeof__" are recognized in all modes.</li>
|
||||
<li>The Apple "blocks" extension is recognized by default in gnu* modes
|
||||
on some platforms; it can be enabled in any mode with the "-fblocks"
|
||||
option.</li>
|
||||
<li>Some warnings are different.</li>
|
||||
</ul>
|
||||
|
||||
<p>Differences between *89 and *99 modes:</p>
|
||||
<ul>
|
||||
<li>The *99 modes default to implementing "inline" as specified in C99, while
|
||||
the *89 modes implement the GNU version. This can be overridden for individual
|
||||
functions with the __gnu_inline__ attribute.</li>
|
||||
<li>Digraphs are not recognized in c89 mode.</li>
|
||||
<li>The scope of names defined inside a "for", "if", "switch", "while", or "do"
|
||||
statement is different. (example: "if ((struct x {int x;}*)0) {}".)</li>
|
||||
<li>__STDC_VERSION__ is not defined in *89 modes.</li>
|
||||
<li>"inline" is not recognized as a keyword in c89 mode.</li>
|
||||
<li>"restrict" is not recognized as a keyword in *89 modes.</li>
|
||||
<li>Commas are allowed in integer constant expressions in *99 modes.</li>
|
||||
<li>Arrays which are not lvalues are not implicitly promoted to pointers in
|
||||
*89 modes.</li>
|
||||
<li>Some warnings are different.</li>
|
||||
</ul>
|
||||
|
||||
<p>c94 mode is identical to c89 mode except that digraphs are enabled in
|
||||
c94 mode (FIXME: And __STDC_VERSION__ should be defined!).</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="c_unimpl_gcc">GCC extensions not implemented yet</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>clang tries to be compatible with gcc as much as possible, but some gcc
|
||||
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 attributes on function pointers
|
||||
(<a href="http://llvm.org/bugs/show_bug.cgi?id=2461">bug 2461</a>). This is
|
||||
a relatively important 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
|
||||
the uses described in the bug, this is likely to be implemented at some
|
||||
point, at least partially.</li>
|
||||
|
||||
<li>clang does not support #pragma align
|
||||
(<a href="http://llvm.org/bugs/show_bug.cgi?id=3811">bug 3811</a>). This is a
|
||||
relatively small feature, so it is likely to be implemented relatively
|
||||
soon.</li>
|
||||
|
||||
<li>clang does not support code generation for local variables pinned to
|
||||
registers (<a href="http://llvm.org/bugs/show_bug.cgi?id=3933">bug 3933</a>).
|
||||
This is a relatively small feature, so it is likely to be implemented
|
||||
relatively soon.</li>
|
||||
|
||||
<li>clang does not support decimal floating point types (_Decimal32 and
|
||||
friends) or fixed-point types (_Fract and friends); nobody has expressed
|
||||
interest in these features yet, so it's hard to say when they will be
|
||||
implemented.</li>
|
||||
|
||||
<li>clang does not support nested functions; this is a complex feature which
|
||||
is infrequently used, so it is unlikely to be implemented anytime soon.</li>
|
||||
|
||||
<li>clang does not support __builtin_apply and friends; this extension requires
|
||||
complex code generator support that does not currently exist in LLVM, and there
|
||||
is very little demand, so it is unlikely to be implemented anytime soon.</li>
|
||||
|
||||
<li>clang does not support global register variables, this is unlikely
|
||||
to be implemented soon.</li>
|
||||
|
||||
<li>clang does not support static initialization of flexible array
|
||||
members. This appears to be a rarely used extension, but could be
|
||||
implemented pending user demand.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>This is not a complete list; if you find an unsupported extension
|
||||
missing from this list, please send an e-mail to cfe-dev. This list
|
||||
currently excludes C++; see <a href="#cxx">C++ Language Features</a>.
|
||||
Also, this list does not include bugs in mostly-implemented features; please
|
||||
see the <a href="http://llvm.org/bugs/buglist.cgi?quicksearch=product%3Aclang+component%3A-New%2BBugs%2CAST%2CBasic%2CDriver%2CHeaders%2CLLVM%2BCodeGen%2Cparser%2Cpreprocessor%2CSemantic%2BAnalyzer">
|
||||
bug tracker</a> for known existing bugs (FIXME: Is there a section for
|
||||
bug-reporting guidelines somewhere?).</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="c_unsupp_gcc">Intentionally unsupported GCC extensions</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>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
|
||||
to implement, two, the extension is completely undocumented, and three, the
|
||||
extension appears to be very rarely used.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="c_ms">Microsoft extensions</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>clang has some experimental support for extensions from
|
||||
Microsoft Visual C++; to enable it, use the -fms-extensions command-line
|
||||
option. Eventually, this will be the default for Windows targets.
|
||||
These extensions are not anywhere near complete, so please do not
|
||||
file bugs; patches are welcome, though.</p>
|
||||
|
||||
<li>clang does not support the Microsoft extension where anonymous
|
||||
record members can be declared using user defined typedefs.</li>
|
||||
|
||||
<li>clang supports the Microsoft "#pragma pack" feature for
|
||||
controlling record layout. GCC also contains support for this feature,
|
||||
however where MSVC and GCC are incompatible clang follows the MSVC
|
||||
definition.</li>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="objc">Objective-C Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="objc_incompatibilities">Intentional Incompatibilities with GCC</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>No cast of super, no lvalue casts.</p>
|
||||
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="cxx">C++ Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>At this point, Clang C++ is not generally useful. However, Clang C++ support
|
||||
is under active development and is progressing rapidly. Please see the <a
|
||||
href="http://clang.llvm.org/cxx_status.html">C++ Status</a> page for details or
|
||||
ask on the mailing list about how you can help.</p>
|
||||
|
||||
<p>Note that the clang driver will refuse to even try to use clang to compile
|
||||
C++ code unless you pass the <tt>-ccc-clang-cxx</tt> option to the driver. If
|
||||
you really want to play with Clang's C++ support, please pass that flag. </p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="objcxx">Objective C++ Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>At this point, Clang C++ support is not generally useful (and therefore,
|
||||
neither is Objective-C++). Please see the <a href="#cxx">C++ section</a> for
|
||||
more information.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="target_features">Target-Specific Features and Limitations</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="target_arch">CPU Architectures Features and Limitations</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<!-- ======================== -->
|
||||
<h4 id="target_arch_x86">X86</h4>
|
||||
<!-- ======================== -->
|
||||
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="target_os">Operating System Features and Limitations</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<!-- ======================================= -->
|
||||
<h4 id="target_os_darwin">Darwin (Mac OS/X)</h4>
|
||||
<!-- ======================================= -->
|
||||
|
||||
<p>No __thread support, 64-bit ObjC support requires SL tools.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
1230
docs/doxygen.cfg
Normal file
1230
docs/doxygen.cfg
Normal file
File diff suppressed because it is too large
Load Diff
1230
docs/doxygen.cfg.in
Normal file
1230
docs/doxygen.cfg.in
Normal file
File diff suppressed because it is too large
Load Diff
378
docs/doxygen.css
Normal file
378
docs/doxygen.css
Normal file
@ -0,0 +1,378 @@
|
||||
BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
|
||||
font-family: Verdana,Geneva,Arial,Helvetica,sans-serif;
|
||||
}
|
||||
BODY,TD {
|
||||
font-size: 90%;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
font-style: italic;
|
||||
}
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
CAPTION { font-weight: bold }
|
||||
DIV.qindex {
|
||||
width: 100%;
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.nav {
|
||||
width: 100%;
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.navtab {
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
margin-right: 15px;
|
||||
padding: 2px;
|
||||
}
|
||||
TD.navtab {
|
||||
font-size: 70%;
|
||||
}
|
||||
A.qindex {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D;
|
||||
}
|
||||
A.qindex:visited {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D
|
||||
}
|
||||
A.qindex:hover {
|
||||
text-decoration: none;
|
||||
background-color: #ddddff;
|
||||
}
|
||||
A.qindexHL {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
border: 1px double #9295C2;
|
||||
}
|
||||
A.qindexHL:hover {
|
||||
text-decoration: none;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
}
|
||||
A.qindexHL:visited {
|
||||
text-decoration: none; background-color: #6666cc; color: #ffffff }
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.codeRef:link { font-weight: normal; color: #0000FF}
|
||||
A.codeRef:visited { font-weight: normal; color: #0000FF}
|
||||
A:hover { text-decoration: none; background-color: #f2f2ff }
|
||||
DL.el { margin-left: -1cm }
|
||||
.fragment {
|
||||
font-family: Fixed, monospace;
|
||||
font-size: 95%;
|
||||
}
|
||||
PRE.fragment {
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #f5f5f5;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
margin-left: 2px;
|
||||
margin-right: 8px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
|
||||
TD.md { background-color: #F4F4FB; font-weight: bold; }
|
||||
TD.mdPrefix {
|
||||
background-color: #F4F4FB;
|
||||
color: #606060;
|
||||
font-size: 80%;
|
||||
}
|
||||
TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; }
|
||||
TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; }
|
||||
DIV.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
|
||||
BODY {
|
||||
background: white;
|
||||
color: black;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
TD.indexkey {
|
||||
background-color: #eeeeff;
|
||||
font-weight: bold;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TD.indexvalue {
|
||||
background-color: #eeeeff;
|
||||
font-style: italic;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TR.memlist {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
P.formulaDsp { text-align: center; }
|
||||
IMG.formulaDsp { }
|
||||
IMG.formulaInl { vertical-align: middle; }
|
||||
SPAN.keyword { color: #008000 }
|
||||
SPAN.keywordtype { color: #604020 }
|
||||
SPAN.keywordflow { color: #e08000 }
|
||||
SPAN.comment { color: #800000 }
|
||||
SPAN.preprocessor { color: #806020 }
|
||||
SPAN.stringliteral { color: #002080 }
|
||||
SPAN.charliteral { color: #008080 }
|
||||
.mdTable {
|
||||
border: 1px solid #868686;
|
||||
background-color: #F4F4FB;
|
||||
}
|
||||
.mdRow {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
.mdescLeft {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.mdescRight {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.memItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplParams {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
color: #606060;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.search { color: #003399;
|
||||
font-weight: bold;
|
||||
}
|
||||
FORM.search {
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
INPUT.search { font-size: 75%;
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
background-color: #eeeeff;
|
||||
}
|
||||
TD.tiny { font-size: 75%;
|
||||
}
|
||||
a {
|
||||
color: #252E78;
|
||||
}
|
||||
a:visited {
|
||||
color: #3D2185;
|
||||
}
|
||||
.dirtab { padding: 4px;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #b0b0b0;
|
||||
}
|
||||
TH.dirtab { background: #eeeeff;
|
||||
font-weight: bold;
|
||||
}
|
||||
HR { height: 1px;
|
||||
border: none;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
/*
|
||||
* LLVM Modifications.
|
||||
* Note: Everything above here is generated with "doxygen -w htlm" command. See
|
||||
* "doxygen --help" for details. What follows are CSS overrides for LLVM
|
||||
* specific formatting. We want to keep the above so it can be replaced with
|
||||
* subsequent doxygen upgrades.
|
||||
*/
|
||||
|
||||
.footer {
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.title {
|
||||
font-size: 25pt;
|
||||
color: black; background: url("http://llvm.org/img/lines.gif");
|
||||
font-weight: bold;
|
||||
border-width: 1px;
|
||||
border-style: solid none solid none;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
padding-left: 8pt;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 2px
|
||||
}
|
||||
A:link {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:visited {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:active {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
font-style: italic;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
font-style: italic;
|
||||
}
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
A.qindex {}
|
||||
A.qindexRef {}
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code { text-decoration: none; font-weight: normal; color: #4444ee }
|
||||
A.codeRef { font-weight: normal; color: #4444ee }
|
10
docs/doxygen.footer
Normal file
10
docs/doxygen.footer
Normal file
@ -0,0 +1,10 @@
|
||||
<hr>
|
||||
<p class="footer">
|
||||
Generated on $datetime by <a href="http://www.doxygen.org">Doxygen
|
||||
$doxygenversion</a>.</p>
|
||||
|
||||
<p class="footer">
|
||||
See the <a href="http://clang.llvm.org">Main Clang Web Page</a> for more
|
||||
information.</p>
|
||||
</body>
|
||||
</html>
|
9
docs/doxygen.header
Normal file
9
docs/doxygen.header
Normal file
@ -0,0 +1,9 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
|
||||
<meta name="keywords" content="clang,LLVM,Low Level Virtual Machine,C,C++,doxygen,API,frontend,documentation"/>
|
||||
<meta name="description" content="C++ source code API documentation for clang."/>
|
||||
<title>clang: $title</title>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
|
||||
</head><body>
|
||||
<p class="title">clang API Documentation</p>
|
15
docs/doxygen.intro
Normal file
15
docs/doxygen.intro
Normal file
@ -0,0 +1,15 @@
|
||||
/// @mainpage clang
|
||||
///
|
||||
/// @section main_intro Introduction
|
||||
/// Welcome to the clang project.
|
||||
///
|
||||
/// This documentation describes the @b internal software that makes
|
||||
/// up clang, not the @b external use of clang. There are no instructions
|
||||
/// here on how to use clang, only the APIs that make up the software. For
|
||||
/// usage instructions, please see the programmer's guide or reference
|
||||
/// manual.
|
||||
///
|
||||
/// @section main_caveat Caveat
|
||||
/// This documentation is generated directly from the source code with doxygen.
|
||||
/// Since clang is constantly under active development, what you're about to
|
||||
/// read is out of date!
|
4
docs/index.html
Normal file
4
docs/index.html
Normal file
@ -0,0 +1,4 @@
|
||||
<title>'clang' C frontend documentation</title>
|
||||
|
||||
None yet, sorry :(
|
||||
|
112
docs/tools/Makefile
Normal file
112
docs/tools/Makefile
Normal file
@ -0,0 +1,112 @@
|
||||
##===- docs/tools/Makefile ---------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
ifdef BUILD_FOR_WEBSITE
|
||||
|
||||
# FIXME: This was copied from the CommandGuide makefile. Figure out
|
||||
# how to get this stuff on the website.
|
||||
|
||||
# This special case is for keeping the CommandGuide on the LLVM web site
|
||||
# up to date automatically as the documents are checked in. It must build
|
||||
# the POD files to HTML only and keep them in the src directories. It must also
|
||||
# build in an unconfigured tree, hence the ifdef. To use this, run
|
||||
# make -s BUILD_FOR_WEBSITE=1 inside the cvs commit script.
|
||||
SRC_DOC_DIR=
|
||||
DST_HTML_DIR=html/
|
||||
DST_MAN_DIR=man/man1/
|
||||
DST_PS_DIR=ps/
|
||||
|
||||
# If we are in BUILD_FOR_WEBSITE mode, default to the all target.
|
||||
all:: html man ps
|
||||
|
||||
clean:
|
||||
rm -f pod2htm*.*~~ $(HTML) $(MAN) $(PS)
|
||||
|
||||
# To create other directories, as needed, and timestamp their creation
|
||||
%/.dir:
|
||||
-mkdir $* > /dev/null
|
||||
date > $@
|
||||
|
||||
else
|
||||
|
||||
# Otherwise, if not in BUILD_FOR_WEBSITE mode, use the project info.
|
||||
LEVEL := ../../../..
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
SRC_DOC_DIR=$(PROJ_SRC_DIR)/
|
||||
DST_HTML_DIR=$(PROJ_OBJ_DIR)/
|
||||
DST_MAN_DIR=$(PROJ_OBJ_DIR)/
|
||||
DST_PS_DIR=$(PROJ_OBJ_DIR)/
|
||||
|
||||
endif
|
||||
|
||||
|
||||
POD := $(wildcard $(SRC_DOC_DIR)*.pod)
|
||||
HTML := $(patsubst $(SRC_DOC_DIR)%.pod, $(DST_HTML_DIR)%.html, $(POD))
|
||||
MAN := $(patsubst $(SRC_DOC_DIR)%.pod, $(DST_MAN_DIR)%.1, $(POD))
|
||||
PS := $(patsubst $(SRC_DOC_DIR)%.pod, $(DST_PS_DIR)%.ps, $(POD))
|
||||
|
||||
ifdef ONLY_MAN_DOCS
|
||||
INSTALL_TARGETS := install-man
|
||||
else
|
||||
INSTALL_TARGETS := install-html install-man install-ps
|
||||
endif
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .html .pod .1 .ps
|
||||
|
||||
$(DST_HTML_DIR)%.html: %.pod $(DST_HTML_DIR)/.dir
|
||||
pod2html --css=manpage.css --htmlroot=. \
|
||||
--podpath=. --infile=$< --outfile=$@ --title=$*
|
||||
|
||||
$(DST_MAN_DIR)%.1: %.pod $(DST_MAN_DIR)/.dir
|
||||
pod2man --release "clang 1.0" --center="Clang Tools Documentation" $< $@
|
||||
|
||||
$(DST_PS_DIR)%.ps: $(DST_MAN_DIR)%.1 $(DST_PS_DIR)/.dir
|
||||
groff -Tps -man $< > $@
|
||||
|
||||
|
||||
html: $(HTML)
|
||||
man: $(MAN)
|
||||
ps: $(PS)
|
||||
|
||||
EXTRA_DIST := $(POD)
|
||||
|
||||
clean-local::
|
||||
$(Verb) $(RM) -f pod2htm*.*~~ $(HTML) $(MAN) $(PS)
|
||||
|
||||
HTML_DIR := $(PROJ_docsdir)/html/clang
|
||||
MAN_DIR := $(PROJ_mandir)/man1
|
||||
PS_DIR := $(PROJ_docsdir)/ps
|
||||
|
||||
install-html:: $(HTML)
|
||||
$(Echo) Installing HTML Clang Tools Documentation
|
||||
$(Verb) $(MKDIR) $(HTML_DIR)
|
||||
$(Verb) $(DataInstall) $(HTML) $(HTML_DIR)
|
||||
$(Verb) $(DataInstall) $(PROJ_SRC_DIR)/manpage.css $(HTML_DIR)
|
||||
|
||||
install-man:: $(MAN)
|
||||
$(Echo) Installing MAN Clang Tools Documentation
|
||||
$(Verb) $(MKDIR) $(MAN_DIR)
|
||||
$(Verb) $(DataInstall) $(MAN) $(MAN_DIR)
|
||||
|
||||
install-ps:: $(PS)
|
||||
$(Echo) Installing PS Clang Tools Documentation
|
||||
$(Verb) $(MKDIR) $(PS_DIR)
|
||||
$(Verb) $(DataInstall) $(PS) $(PS_DIR)
|
||||
|
||||
install-local:: $(INSTALL_TARGETS)
|
||||
|
||||
uninstall-local::
|
||||
$(Echo) Uninstalling Clang Tools Documentation
|
||||
$(Verb) $(RM) -rf $(HTML_DIR) $(MAN_DIR) $(PS_DIR)
|
||||
|
||||
printvars::
|
||||
$(Echo) "POD : " '$(POD)'
|
||||
$(Echo) "HTML : " '$(HTML)'
|
514
docs/tools/clang.pod
Normal file
514
docs/tools/clang.pod
Normal file
@ -0,0 +1,514 @@
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
clang - the Clang C and Objective-C compiler
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
|
||||
[B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-O3>|B<-O4>]
|
||||
B<-W>I<warnings...> B<-pedantic>
|
||||
B<-I>I<dir...> B<-L>I<dir...>
|
||||
B<-D>I<macro[=defn]>
|
||||
B<-f>I<feature-option...>
|
||||
B<-m>I<machine-option...>
|
||||
B<-o> I<output-file>
|
||||
I<input-filenames>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<clang> is a 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
|
||||
stages of compilation, to understand how to invoke it. These stages are:
|
||||
|
||||
=over
|
||||
|
||||
=item B<Driver>
|
||||
|
||||
The B<clang> executable is actually a small driver which controls the overall
|
||||
execution of other tools such as the compiler, assembler and linker. Typically
|
||||
you do not need to interact with the driver, but you transparently use it to run
|
||||
the other tools.
|
||||
|
||||
=item B<Preprocessing>
|
||||
|
||||
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.
|
||||
|
||||
=item B<Parsing and Semantic Analysis>
|
||||
|
||||
This stage parses the input file, translating preprocessor tokens into a parse
|
||||
tree. Once in the form of a parser tree, it applies semantic analysis to compute
|
||||
types for expressions as well and determine whether the code is well formed. This
|
||||
stage is responsible for generating most of the compiler warnings as well as
|
||||
parse errors. The output of this stage is an "Abstract Syntax Tree" (AST).
|
||||
|
||||
=item B<Code Generation and Optimization>
|
||||
|
||||
This stage translates an AST into low-level intermediate code (known as "LLVM
|
||||
IR") and ultimately to machine code (depending on the optimization level). This
|
||||
phase is responsible for optimizing the generated code and handling
|
||||
target-specfic code generation. The output of this stage is typically called a
|
||||
".s" file or "assembly" file.
|
||||
|
||||
=item B<Assembler>
|
||||
|
||||
This stage runs the target assembler to translate the output of the compiler
|
||||
into a target object file. The output of this stage is typically called a ".o"
|
||||
file or "object" file.
|
||||
|
||||
=item B<Linker>
|
||||
|
||||
This stage runs the target linker to merge multiple object files into an
|
||||
executable or dynamic library. The output of this stage is typically called an
|
||||
"a.out", ".dylib" or ".so" file.
|
||||
|
||||
=back
|
||||
|
||||
The Clang compiler supports a large number of options to control each of these
|
||||
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
|
||||
same driver.
|
||||
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=head2 Stage Selection Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-E>
|
||||
|
||||
Run the preprocessor stage.
|
||||
|
||||
=item B<-fsyntax-only>
|
||||
|
||||
Run the preprocessor, parser and type checking stages.
|
||||
|
||||
=item B<-S>
|
||||
|
||||
Run the previous stages as well as LLVM generation and optimization stages and
|
||||
target-specific code generation, producing an assembly file.
|
||||
|
||||
=item B<-c>
|
||||
|
||||
Run all of the above, plus the assembler, generating a target ".o" object file.
|
||||
|
||||
=item B<no stage selection option>
|
||||
|
||||
If no stage selection option is specified, all stages above are run, and the
|
||||
linker is run to combine the results into an executable or shared library.
|
||||
|
||||
=item B<--analyze>
|
||||
|
||||
Run the Clang Static Analyzer.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
=head2 Language Selection and Mode Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-x> I<language>
|
||||
|
||||
Treat subsequent input files as having type I<language>.
|
||||
|
||||
=item B<-std>=I<language>
|
||||
|
||||
Specify the language standard to compile for.
|
||||
|
||||
=item B<-ansi>
|
||||
|
||||
Same as B<-std=c89>.
|
||||
|
||||
=item B<-ObjC++>
|
||||
|
||||
Treat source input files as Objective-C++ inputs.
|
||||
|
||||
=item B<-ObjC>
|
||||
|
||||
Treat source input files as Objective-C inputs.
|
||||
|
||||
=item B<-trigraphs>
|
||||
|
||||
Enable trigraphs.
|
||||
|
||||
=item B<-ffreestanding>
|
||||
|
||||
Indicate that the file should be compiled for a freestanding, not a hosted,
|
||||
environment.
|
||||
|
||||
=item B<-fno-builtin>
|
||||
|
||||
Disable special handling and optimizations of builtin functions like strlen and
|
||||
malloc.
|
||||
|
||||
=item B<-fmath-errno>
|
||||
|
||||
Indicate that math functions should be treated as updating errno.
|
||||
|
||||
=item B<-fpascal-strings>
|
||||
|
||||
Enable support for Pascal-style strings with "\pfoo".
|
||||
|
||||
=item B<-fms-extensions>
|
||||
|
||||
Enable support for Microsoft extensions.
|
||||
|
||||
=item B<-fwritable-strings>
|
||||
|
||||
Make all string literals default to writable. This disables uniquing of
|
||||
strings and other optimizations.
|
||||
|
||||
=item B<-flax-vector-conversions>
|
||||
|
||||
Allow loose type checking rules for implicit vector conversions.
|
||||
|
||||
=item B<-fblocks>
|
||||
|
||||
Enable the "Blocks" language feature.
|
||||
|
||||
|
||||
=item B<-fobjc-gc-only>
|
||||
|
||||
Indicate that Objective-C code should be compiled in GC-only mode, which only
|
||||
works when Objective-C Garbage Collection is enabled.
|
||||
|
||||
=item B<-fobjc-gc>
|
||||
|
||||
Indicate that Objective-C code should be compiled in hybrid-GC mode, which works
|
||||
with both GC and non-GC mode.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
=head2 Target Selection Options
|
||||
|
||||
Clang fully supports cross compilation as an inherent part of its design.
|
||||
Depending on how your version of Clang is configured, it may have support for
|
||||
a number of cross compilers, or may only support a native target.
|
||||
|
||||
=over
|
||||
|
||||
=item B<-arch> I<architecture>
|
||||
|
||||
Specify the architecture to build for.
|
||||
|
||||
=item B<-mmacosx-version-min>=I<version>
|
||||
|
||||
When building for Mac OS/X, specify the minimum version supported by your
|
||||
application.
|
||||
|
||||
=item B<-miphoneos-version-min>
|
||||
|
||||
When building for iPhone OS, specify the minimum version supported by your
|
||||
application.
|
||||
|
||||
|
||||
=item B<-march>=I<cpu>
|
||||
|
||||
Specify that Clang should generate code for a specific processor family member
|
||||
and later. For example, if you specify -march=i486, the compiler is allowed to
|
||||
generate instructions that are valid on i486 and later processors, but which
|
||||
may not exist on earlier ones.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Code Generation Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-O0> B<-O1> B<-O2> B<-Os> B<-O3> B<-O4>
|
||||
|
||||
Specify which optimization level to use. B<-O0> means "no optimization": this
|
||||
level compiles the fastest and generates the most debuggable code. B<-O2> is a
|
||||
moderate level of optimization which enables most optimizations. B<-Os> is like
|
||||
B<-O2> with extra optimizations to reduce code size. B<-O3> is like B<-O2>,
|
||||
except that it enables optimizations that take longer to perform or that may
|
||||
generate larger code (in an attempt to make the program run faster). On
|
||||
supported platforms, B<-O4> enables link-time optimization; object files are
|
||||
stored in the LLVM bitcode file format and whole program optimization is done at
|
||||
link time. B<-O1> is somewhere between B<-O0> and B<-O2>.
|
||||
|
||||
=item B<-g>
|
||||
|
||||
Generate debug information. Note that Clang debug information works best at
|
||||
B<-O0>. At higher optimization levels, only line number information is
|
||||
currently available.
|
||||
|
||||
=item B<-fexceptions>
|
||||
|
||||
Enable generation of unwind information, this allows exceptions to be thrown
|
||||
through Clang compiled stack frames. This is on by default in x86-64.
|
||||
|
||||
=item B<-ftrapv>
|
||||
|
||||
Generate code to catch integer overflow errors. Signed integer overflow is
|
||||
undefined in C, with this flag, extra code is generated to detect this and abort
|
||||
when it happens.
|
||||
|
||||
|
||||
=item B<-fvisibility>
|
||||
|
||||
This flag sets the default visibility level.
|
||||
|
||||
=item B<-fcommon>
|
||||
|
||||
This flag specifies that variables without initializers get common linkage. It
|
||||
can be disabled with B<-fno-common>.
|
||||
|
||||
=item B<-flto> B<-emit-llvm>
|
||||
|
||||
Generate output files in LLVM formats, suitable for link time optimization. When
|
||||
used with B<-S> this generates LLVM intermediate language assembly files,
|
||||
otherwise this generates LLVM bitcode format object files (which may be passed
|
||||
to the linker depending on the stage selection options).
|
||||
|
||||
=cut
|
||||
|
||||
##=item B<-fnext-runtime> B<-fobjc-nonfragile-abi> B<-fgnu-runtime>
|
||||
##These options specify which Objective-C runtime the code generator should
|
||||
##target. FIXME: we don't want people poking these generally.
|
||||
|
||||
=pod
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Driver Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-###>
|
||||
|
||||
Print the commands to run for this compilation.
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Display available options.
|
||||
|
||||
=item B<-Qunused-arguments>
|
||||
|
||||
Don't emit warning for unused driver arguments.
|
||||
|
||||
=item B<-Wa,>I<args>
|
||||
|
||||
Pass the comma separated arguments in I<args> to the assembler.
|
||||
|
||||
=item B<-Wl,>I<args>
|
||||
|
||||
Pass the comma separated arguments in I<args> to the linker.
|
||||
|
||||
=item B<-Wp,>I<args>
|
||||
|
||||
Pass the comma separated arguments in I<args> to the preprocessor.
|
||||
|
||||
=item B<-Xanalyzer> I<arg>
|
||||
|
||||
Pass I<arg> to the static analyzer.
|
||||
|
||||
=item B<-Xassembler> I<arg>
|
||||
|
||||
Pass I<arg> to the assembler.
|
||||
|
||||
=item B<-Xclang> I<arg>
|
||||
|
||||
Pass I<arg> to the clang compiler.
|
||||
|
||||
=item B<-Xlinker> I<arg>
|
||||
|
||||
Pass I<arg> to the linker.
|
||||
|
||||
=item B<-Xpreprocessor> I<arg>
|
||||
|
||||
Pass I<arg> to the preprocessor.
|
||||
|
||||
=item B<-o> I<file>
|
||||
|
||||
Write output to I<file>.
|
||||
|
||||
=item B<-print-file-name>=I<file>
|
||||
|
||||
Print the full library path of I<file>.
|
||||
|
||||
=item B<-print-libgcc-file-name>
|
||||
|
||||
Print the library path for "libgcc.a".
|
||||
|
||||
=item B<-print-prog-name>=I<name>
|
||||
|
||||
Print the full program path of I<name>.
|
||||
|
||||
=item B<-print-search-dirs>
|
||||
|
||||
Print the paths used for finding libraries and programs.
|
||||
|
||||
=item B<-save-temps>
|
||||
|
||||
Save intermediate compilation results.
|
||||
|
||||
=item B<-time>
|
||||
|
||||
Time individual commands.
|
||||
|
||||
=item B<-ftime-report>
|
||||
|
||||
Print timing summary of each stage of compilation.
|
||||
|
||||
=item B<-v>
|
||||
|
||||
Show commands to run and use verbose output.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Diagnostics Options
|
||||
|
||||
=over
|
||||
|
||||
=item
|
||||
B<-fshow-column>
|
||||
B<-fshow-source-location>
|
||||
B<-fcaret-diagnostics>
|
||||
B<-fdiagnostics-fixit-info>
|
||||
B<-fdiagnostics-print-source-range-info>
|
||||
B<-fprint-source-range-info>
|
||||
B<-fdiagnostics-show-option>
|
||||
B<-fmessage-length>
|
||||
|
||||
These options control how Clang prints out information about diagnostics (errors
|
||||
and warnings). Please see the Clang User's Manual for more information.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Preprocessor Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-D>I<macroname=value>
|
||||
|
||||
Adds an implicit #define into the predefines buffer which is read before the
|
||||
source file is preprocessed.
|
||||
|
||||
=item B<-U>I<macroname>
|
||||
|
||||
Adds an implicit #undef into the predefines buffer which is read before the
|
||||
source file is preprocessed.
|
||||
|
||||
=item B<-include> I<filename>
|
||||
|
||||
Adds an implicit #include into the predefines buffer which is read before the
|
||||
source file is preprocessed.
|
||||
|
||||
=item B<-I>I<directory>
|
||||
|
||||
Add the specified directory to the search path for include files.
|
||||
|
||||
=item B<-F>I<directory>
|
||||
|
||||
Add the specified directory to the search path for framework include files.
|
||||
|
||||
=item B<-nostdinc>
|
||||
|
||||
Do not search the standard system directories for include files.
|
||||
|
||||
=cut
|
||||
|
||||
## TODO, but do we really want people using this stuff?
|
||||
=item B<-idirafter>I<directory>
|
||||
=item B<-iquote>I<directory>
|
||||
=item B<-isystem>I<directory>
|
||||
=item B<-iprefix>I<directory>
|
||||
=item B<-iwithprefix>I<directory>
|
||||
=item B<-iwithprefixbefore>I<directory>
|
||||
=item B<-isysroot>
|
||||
=pod
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
### TODO someday.
|
||||
=head2 Warning Control Options
|
||||
=over
|
||||
=back
|
||||
=head2 Code Generation and Optimization Options
|
||||
=over
|
||||
=back
|
||||
=head2 Assembler Options
|
||||
=over
|
||||
=back
|
||||
=head2 Linker Options
|
||||
=over
|
||||
=back
|
||||
=head2 Static Analyzer Options
|
||||
=over
|
||||
=back
|
||||
|
||||
=pod
|
||||
|
||||
|
||||
=head1 ENVIRONMENT
|
||||
|
||||
=over
|
||||
|
||||
=item B<TMPDIR>, B<TEMP>, B<TMP>
|
||||
|
||||
These environment variables are checked, in order, for the location to
|
||||
write temporary files used during the compilation process.
|
||||
|
||||
=item B<CPATH>
|
||||
|
||||
If this environment variable is present, it is treated as a delimited
|
||||
list of paths to be added to the default system include path list. The
|
||||
delimiter is the platform dependent delimitor, as used in the I<PATH>
|
||||
environment variable.
|
||||
|
||||
Empty components in the environment variable are ignored.
|
||||
|
||||
=item B<C_INCLUDE_PATH>, B<OBJC_INCLUDE_PATH>, B<CPLUS_INCLUDE_PATH>,
|
||||
B<OBJCPLUS_INCLUDE_PATH>
|
||||
|
||||
These environment variables specify additional paths, as for CPATH,
|
||||
which are only used when processing the appropriate language.
|
||||
|
||||
=item B<MACOSX_DEPLOYMENT_TARGET>
|
||||
|
||||
If -mmacosx-version-min is unspecified, the default deployment target
|
||||
is read from this environment variable. This option only affects darwin
|
||||
targets.
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Clang currently does not have C++ support, and this manual page is incomplete.
|
||||
To report bugs, please visit L<http://llvm.org/bugs/>. Most bug reports should
|
||||
include preprocessed source files (use the B<-E> option) and the full output of
|
||||
the compiler, along with information to reproduce.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
as(1), ld(1)
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Maintained by the Clang / LLVM Team (L<http://clang.llvm.org>).
|
||||
|
||||
=cut
|
256
docs/tools/manpage.css
Normal file
256
docs/tools/manpage.css
Normal file
@ -0,0 +1,256 @@
|
||||
/* Based on http://www.perldoc.com/css/perldoc.css */
|
||||
|
||||
@import url("../llvm.css");
|
||||
|
||||
body { font-family: Arial,Helvetica; }
|
||||
|
||||
blockquote { margin: 10pt; }
|
||||
|
||||
h1, a { color: #336699; }
|
||||
|
||||
|
||||
/*** Top menu style ****/
|
||||
.mmenuon {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #ff6600; font-size: 10pt;
|
||||
}
|
||||
.mmenuoff {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #ffffff; font-size: 10pt;
|
||||
}
|
||||
.cpyright {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #ffffff; font-size: xx-small;
|
||||
}
|
||||
.cpyrightText {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #ffffff; font-size: xx-small;
|
||||
}
|
||||
.sections {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 11pt;
|
||||
}
|
||||
.dsections {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 12pt;
|
||||
}
|
||||
.slink {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
|
||||
color: #000000; font-size: 9pt;
|
||||
}
|
||||
|
||||
.slink2 { font-family: Arial,Helvetica; text-decoration: none; color: #336699; }
|
||||
|
||||
.maintitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 18pt;
|
||||
}
|
||||
.dblArrow {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: small;
|
||||
}
|
||||
.menuSec {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: small;
|
||||
}
|
||||
|
||||
.newstext {
|
||||
font-family: Arial,Helvetica; font-size: small;
|
||||
}
|
||||
|
||||
.linkmenu {
|
||||
font-family: Arial,Helvetica; color: #000000; font-weight: bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
P {
|
||||
font-family: Arial,Helvetica;
|
||||
}
|
||||
|
||||
PRE {
|
||||
font-size: 10pt;
|
||||
}
|
||||
.quote {
|
||||
font-family: Times; text-decoration: none;
|
||||
color: #000000; font-size: 9pt; font-style: italic;
|
||||
}
|
||||
.smstd { font-family: Arial,Helvetica; color: #000000; font-size: x-small; }
|
||||
.std { font-family: Arial,Helvetica; color: #000000; }
|
||||
.meerkatTitle {
|
||||
font-family: sans-serif; font-size: x-small; color: black; }
|
||||
|
||||
.meerkatDescription { font-family: sans-serif; font-size: 10pt; color: black }
|
||||
.meerkatCategory {
|
||||
font-family: sans-serif; font-size: 9pt; font-weight: bold; font-style: italic;
|
||||
color: brown; }
|
||||
.meerkatChannel {
|
||||
font-family: sans-serif; font-size: 9pt; font-style: italic; color: brown; }
|
||||
.meerkatDate { font-family: sans-serif; font-size: xx-small; color: #336699; }
|
||||
|
||||
.tocTitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #333333; font-size: 10pt;
|
||||
}
|
||||
|
||||
.toc-item {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #336699; font-size: 10pt; text-decoration: underline;
|
||||
}
|
||||
|
||||
.perlVersion {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #336699; font-size: 10pt; text-decoration: none;
|
||||
}
|
||||
|
||||
.podTitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.docTitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #000000; font-size: 10pt;
|
||||
}
|
||||
.dotDot {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #000000; font-size: 9pt;
|
||||
}
|
||||
|
||||
.docSec {
|
||||
font-family: Arial,Helvetica; font-weight: normal;
|
||||
color: #333333; font-size: 9pt;
|
||||
}
|
||||
.docVersion {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 10pt;
|
||||
}
|
||||
|
||||
.docSecs-on {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
|
||||
color: #ff0000; font-size: 10pt;
|
||||
}
|
||||
.docSecs-off {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
|
||||
color: #333333; font-size: 10pt;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: medium;
|
||||
}
|
||||
h1 {
|
||||
font-family: Verdana,Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: large;
|
||||
}
|
||||
|
||||
DL {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
|
||||
color: #333333; font-size: 10pt;
|
||||
}
|
||||
|
||||
UL > LI > A {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #336699; font-size: 10pt;
|
||||
}
|
||||
|
||||
.moduleInfo {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #333333; font-size: 11pt;
|
||||
}
|
||||
|
||||
.moduleInfoSec {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 10pt;
|
||||
}
|
||||
|
||||
.moduleInfoVal {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: underline;
|
||||
color: #000000; font-size: 10pt;
|
||||
}
|
||||
|
||||
.cpanNavTitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #ffffff; font-size: 10pt;
|
||||
}
|
||||
.cpanNavLetter {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #333333; font-size: 9pt;
|
||||
}
|
||||
.cpanCat {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 9pt;
|
||||
}
|
||||
|
||||
.bttndrkblue-bkgd-top {
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgtop.gif);
|
||||
}
|
||||
.bttndrkblue-bkgd-left {
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgleft.gif);
|
||||
}
|
||||
.bttndrkblue-bkgd {
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
background-repeat: no-repeat;
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgmiddle.gif);
|
||||
vertical-align: top;
|
||||
}
|
||||
.bttndrkblue-bkgd-right {
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgright.gif);
|
||||
}
|
||||
.bttndrkblue-bkgd-bottom {
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgbottom.gif);
|
||||
}
|
||||
.bttndrkblue-text a {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
a.bttndrkblue-text:hover {
|
||||
color: #ffDD3C;
|
||||
text-decoration: none;
|
||||
}
|
||||
.bg-ltblue {
|
||||
background-color: #f0f5fa;
|
||||
}
|
||||
|
||||
.border-left-b {
|
||||
background: #f0f5fa url(/i/corner-leftline.gif) repeat-y;
|
||||
}
|
||||
|
||||
.border-right-b {
|
||||
background: #f0f5fa url(/i/corner-rightline.gif) repeat-y;
|
||||
}
|
||||
|
||||
.border-top-b {
|
||||
background: #f0f5fa url(/i/corner-topline.gif) repeat-x;
|
||||
}
|
||||
|
||||
.border-bottom-b {
|
||||
background: #f0f5fa url(/i/corner-botline.gif) repeat-x;
|
||||
}
|
||||
|
||||
.border-right-w {
|
||||
background: #ffffff url(/i/corner-rightline.gif) repeat-y;
|
||||
}
|
||||
|
||||
.border-top-w {
|
||||
background: #ffffff url(/i/corner-topline.gif) repeat-x;
|
||||
}
|
||||
|
||||
.border-bottom-w {
|
||||
background: #ffffff url(/i/corner-botline.gif) repeat-x;
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.border-left-w {
|
||||
background: #ffffff url(/i/corner-leftline.gif) repeat-y;
|
||||
}
|
1
include/CMakeLists.txt
Normal file
1
include/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(clang)
|
4
include/Makefile
Normal file
4
include/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
LEVEL = ../../..
|
||||
DIRS := clang
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
253
include/clang/AST/APValue.h
Normal file
253
include/clang/AST/APValue.h
Normal file
@ -0,0 +1,253 @@
|
||||
//===--- APValue.h - Union class for APFloat/APSInt/Complex -----*- 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 APValue class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_APVALUE_H
|
||||
#define LLVM_CLANG_AST_APVALUE_H
|
||||
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
|
||||
namespace clang {
|
||||
class Expr;
|
||||
|
||||
/// APValue - This class implements a discriminated union of [uninitialized]
|
||||
/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset].
|
||||
class APValue {
|
||||
typedef llvm::APSInt APSInt;
|
||||
typedef llvm::APFloat APFloat;
|
||||
public:
|
||||
enum ValueKind {
|
||||
Uninitialized,
|
||||
Int,
|
||||
Float,
|
||||
ComplexInt,
|
||||
ComplexFloat,
|
||||
LValue,
|
||||
Vector
|
||||
};
|
||||
private:
|
||||
ValueKind Kind;
|
||||
|
||||
struct ComplexAPSInt {
|
||||
APSInt Real, Imag;
|
||||
ComplexAPSInt() : Real(1), Imag(1) {}
|
||||
};
|
||||
struct ComplexAPFloat {
|
||||
APFloat Real, Imag;
|
||||
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
|
||||
};
|
||||
|
||||
struct LV {
|
||||
Expr* Base;
|
||||
uint64_t Offset;
|
||||
};
|
||||
struct Vec {
|
||||
APValue *Elts;
|
||||
unsigned NumElts;
|
||||
Vec() : Elts(0), NumElts(0) {}
|
||||
~Vec() { delete[] Elts; }
|
||||
};
|
||||
|
||||
enum {
|
||||
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
|
||||
sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat))
|
||||
};
|
||||
|
||||
/// Data - space for the largest member in units of void*. This is an effort
|
||||
/// to ensure that the APSInt/APFloat values have proper alignment.
|
||||
void *Data[(MaxSize+sizeof(void*)-1)/sizeof(void*)];
|
||||
|
||||
public:
|
||||
APValue() : Kind(Uninitialized) {}
|
||||
explicit APValue(const APSInt &I) : Kind(Uninitialized) {
|
||||
MakeInt(); setInt(I);
|
||||
}
|
||||
explicit APValue(const APFloat &F) : Kind(Uninitialized) {
|
||||
MakeFloat(); setFloat(F);
|
||||
}
|
||||
explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) {
|
||||
MakeVector(); setVector(E, N);
|
||||
}
|
||||
APValue(const APSInt &R, const APSInt &I) : Kind(Uninitialized) {
|
||||
MakeComplexInt(); setComplexInt(R, I);
|
||||
}
|
||||
APValue(const APFloat &R, const APFloat &I) : Kind(Uninitialized) {
|
||||
MakeComplexFloat(); setComplexFloat(R, I);
|
||||
}
|
||||
APValue(const APValue &RHS) : Kind(Uninitialized) {
|
||||
*this = RHS;
|
||||
}
|
||||
APValue(Expr* B, uint64_t O) : Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, O);
|
||||
}
|
||||
~APValue() {
|
||||
MakeUninit();
|
||||
}
|
||||
|
||||
ValueKind getKind() const { return Kind; }
|
||||
bool isUninit() const { return Kind == Uninitialized; }
|
||||
bool isInt() const { return Kind == Int; }
|
||||
bool isFloat() const { return Kind == Float; }
|
||||
bool isComplexInt() const { return Kind == ComplexInt; }
|
||||
bool isComplexFloat() const { return Kind == ComplexFloat; }
|
||||
bool isLValue() const { return Kind == LValue; }
|
||||
bool isVector() const { return Kind == Vector; }
|
||||
|
||||
void print(llvm::raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
APSInt &getInt() {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
return *(APSInt*)(void*)Data;
|
||||
}
|
||||
const APSInt &getInt() const {
|
||||
return const_cast<APValue*>(this)->getInt();
|
||||
}
|
||||
|
||||
APFloat &getFloat() {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
return *(APFloat*)(void*)Data;
|
||||
}
|
||||
const APFloat &getFloat() const {
|
||||
return const_cast<APValue*>(this)->getFloat();
|
||||
}
|
||||
|
||||
APValue &getVectorElt(unsigned i) const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((Vec*)(void*)Data)->Elts[i];
|
||||
}
|
||||
unsigned getVectorLength() const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((Vec*)(void *)Data)->NumElts;
|
||||
}
|
||||
|
||||
APSInt &getComplexIntReal() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(void*)Data)->Real;
|
||||
}
|
||||
const APSInt &getComplexIntReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntReal();
|
||||
}
|
||||
|
||||
APSInt &getComplexIntImag() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(void*)Data)->Imag;
|
||||
}
|
||||
const APSInt &getComplexIntImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntImag();
|
||||
}
|
||||
|
||||
APFloat &getComplexFloatReal() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(void*)Data)->Real;
|
||||
}
|
||||
const APFloat &getComplexFloatReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatReal();
|
||||
}
|
||||
|
||||
APFloat &getComplexFloatImag() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(void*)Data)->Imag;
|
||||
}
|
||||
const APFloat &getComplexFloatImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatImag();
|
||||
}
|
||||
|
||||
Expr* getLValueBase() const {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
return ((const LV*)(const void*)Data)->Base;
|
||||
}
|
||||
uint64_t getLValueOffset() const {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
return ((const LV*)(const void*)Data)->Offset;
|
||||
}
|
||||
|
||||
void setInt(const APSInt &I) {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
*(APSInt*)(void*)Data = I;
|
||||
}
|
||||
void setFloat(const APFloat &F) {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
*(APFloat*)(void*)Data = F;
|
||||
}
|
||||
void setVector(const APValue *E, unsigned N) {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
((Vec*)(void*)Data)->Elts = new APValue[N];
|
||||
((Vec*)(void*)Data)->NumElts = N;
|
||||
for (unsigned i = 0; i != N; ++i)
|
||||
((Vec*)(void*)Data)->Elts[i] = E[i];
|
||||
}
|
||||
void setComplexInt(const APSInt &R, const APSInt &I) {
|
||||
assert(R.getBitWidth() == I.getBitWidth() &&
|
||||
"Invalid complex int (type mismatch).");
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
((ComplexAPSInt*)(void*)Data)->Real = R;
|
||||
((ComplexAPSInt*)(void*)Data)->Imag = I;
|
||||
}
|
||||
void setComplexFloat(const APFloat &R, const APFloat &I) {
|
||||
assert(&R.getSemantics() == &I.getSemantics() &&
|
||||
"Invalid complex float (type mismatch).");
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
((ComplexAPFloat*)(void*)Data)->Real = R;
|
||||
((ComplexAPFloat*)(void*)Data)->Imag = I;
|
||||
}
|
||||
void setLValue(Expr *B, uint64_t O) {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
((LV*)(void*)Data)->Base = B;
|
||||
((LV*)(void*)Data)->Offset = O;
|
||||
}
|
||||
|
||||
const APValue &operator=(const APValue &RHS);
|
||||
|
||||
private:
|
||||
void MakeUninit();
|
||||
void MakeInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)Data) APSInt(1);
|
||||
Kind = Int;
|
||||
}
|
||||
void MakeFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((APFloat*)(void*)Data) APFloat(0.0);
|
||||
Kind = Float;
|
||||
}
|
||||
void MakeVector() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((Vec*)(void*)Data) Vec();
|
||||
Kind = Vector;
|
||||
}
|
||||
void MakeComplexInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((ComplexAPSInt*)(void*)Data) ComplexAPSInt();
|
||||
Kind = ComplexInt;
|
||||
}
|
||||
void MakeComplexFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((ComplexAPFloat*)(void*)Data) ComplexAPFloat();
|
||||
Kind = ComplexFloat;
|
||||
}
|
||||
void MakeLValue() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((LV*)(void*)Data) LV();
|
||||
Kind = LValue;
|
||||
}
|
||||
};
|
||||
|
||||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) {
|
||||
V.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
28
include/clang/AST/AST.h
Normal file
28
include/clang/AST/AST.h
Normal file
@ -0,0 +1,28 @@
|
||||
//===--- AST.h - "Umbrella" header for AST library --------------*- 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 interface to the AST classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_AST_H
|
||||
#define LLVM_CLANG_AST_AST_H
|
||||
|
||||
// This header exports all AST interfaces.
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
|
||||
#endif
|
81
include/clang/AST/ASTConsumer.h
Normal file
81
include/clang/AST/ASTConsumer.h
Normal file
@ -0,0 +1,81 @@
|
||||
//===--- ASTConsumer.h - Abstract interface for reading ASTs ----*- 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 ASTConsumer class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ASTCONSUMER_H
|
||||
#define LLVM_CLANG_AST_ASTCONSUMER_H
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class DeclGroupRef;
|
||||
class TagDecl;
|
||||
class HandleTagDeclDefinition;
|
||||
class SemaConsumer; // layering violation required for safe SemaConsumer
|
||||
class VarDecl;
|
||||
|
||||
/// ASTConsumer - This is an abstract interface that should be implemented by
|
||||
/// clients that read ASTs. This abstraction layer allows the client to be
|
||||
/// independent of the AST producer (e.g. parser vs AST dump file reader, etc).
|
||||
class ASTConsumer {
|
||||
/// \brief Whether this AST consumer also requires information about
|
||||
/// semantic analysis.
|
||||
bool SemaConsumer;
|
||||
|
||||
friend class SemaConsumer;
|
||||
|
||||
public:
|
||||
ASTConsumer() : SemaConsumer(false) { }
|
||||
|
||||
virtual ~ASTConsumer() {}
|
||||
|
||||
/// Initialize - This is called to initialize the consumer, providing the
|
||||
/// ASTContext and the Action.
|
||||
virtual void Initialize(ASTContext &Context) {}
|
||||
|
||||
/// HandleTopLevelDecl - Handle the specified top-level declaration. This is
|
||||
/// called by the parser to process every top-level Decl*. Note that D can
|
||||
/// be the head of a chain of Decls (e.g. for `int a, b` the chain will have
|
||||
/// two elements). Use Decl::getNextDeclarator() to walk the chain.
|
||||
virtual void HandleTopLevelDecl(DeclGroupRef D);
|
||||
|
||||
/// HandleTranslationUnit - This method is called when the ASTs for entire
|
||||
/// translation unit have been parsed.
|
||||
virtual void HandleTranslationUnit(ASTContext &Ctx) {}
|
||||
|
||||
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
|
||||
/// (e.g. struct, union, enum, class) is completed. This allows the client to
|
||||
/// hack on the type, which can occur at any point in the file (because these
|
||||
/// can be defined in declspecs).
|
||||
virtual void HandleTagDeclDefinition(TagDecl *D) {}
|
||||
|
||||
/// \brief Callback invoked at the end of a translation unit to
|
||||
/// notify the consumer that the given tentative definition should
|
||||
/// be completed.
|
||||
///
|
||||
/// The variable declaration itself will be a tentative
|
||||
/// definition. If it had an incomplete array type, its type will
|
||||
/// have already been changed to an array of size 1. However, the
|
||||
/// declaration remains a tentative definition and has not been
|
||||
/// modified by the introduction of an implicit zero initializer.
|
||||
virtual void CompleteTentativeDefinition(VarDecl *D) {}
|
||||
|
||||
/// PrintStats - If desired, print any statistics.
|
||||
virtual void PrintStats() {
|
||||
}
|
||||
|
||||
// Support isa/cast/dyn_cast
|
||||
static bool classof(const ASTConsumer *) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
857
include/clang/AST/ASTContext.h
Normal file
857
include/clang/AST/ASTContext.h
Normal file
@ -0,0 +1,857 @@
|
||||
//===--- ASTContext.h - Context to hold long-lived AST nodes ----*- 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 ASTContext interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
|
||||
#define LLVM_CLANG_AST_ASTCONTEXT_H
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Builtins.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
struct fltSemantics;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class FileManager;
|
||||
class ASTRecordLayout;
|
||||
class Expr;
|
||||
class ExternalASTSource;
|
||||
class IdentifierTable;
|
||||
class SelectorTable;
|
||||
class SourceManager;
|
||||
class TargetInfo;
|
||||
// Decls
|
||||
class Decl;
|
||||
class ObjCPropertyDecl;
|
||||
class RecordDecl;
|
||||
class TagDecl;
|
||||
class TranslationUnitDecl;
|
||||
class TypeDecl;
|
||||
class TypedefDecl;
|
||||
class TemplateTypeParmDecl;
|
||||
class FieldDecl;
|
||||
class ObjCIvarRefExpr;
|
||||
class ObjCIvarDecl;
|
||||
|
||||
/// ASTContext - This class holds long-lived AST nodes (such as types and
|
||||
/// decls) that can be referred to throughout the semantic analysis of a file.
|
||||
class ASTContext {
|
||||
std::vector<Type*> Types;
|
||||
llvm::FoldingSet<ExtQualType> ExtQualTypes;
|
||||
llvm::FoldingSet<ComplexType> ComplexTypes;
|
||||
llvm::FoldingSet<PointerType> PointerTypes;
|
||||
llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
|
||||
llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
|
||||
llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
|
||||
llvm::FoldingSet<MemberPointerType> MemberPointerTypes;
|
||||
llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;
|
||||
llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
|
||||
std::vector<VariableArrayType*> VariableArrayTypes;
|
||||
std::vector<DependentSizedArrayType*> DependentSizedArrayTypes;
|
||||
llvm::FoldingSet<VectorType> VectorTypes;
|
||||
llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes;
|
||||
llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes;
|
||||
llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
|
||||
llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes;
|
||||
llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes;
|
||||
llvm::FoldingSet<TypenameType> TypenameTypes;
|
||||
llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes;
|
||||
llvm::FoldingSet<ObjCQualifiedIdType> ObjCQualifiedIdTypes;
|
||||
|
||||
llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
|
||||
llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
|
||||
|
||||
/// \brief The set of nested name specifiers.
|
||||
///
|
||||
/// This set is managed by the NestedNameSpecifier class.
|
||||
llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers;
|
||||
NestedNameSpecifier *GlobalNestedNameSpecifier;
|
||||
friend class NestedNameSpecifier;
|
||||
|
||||
/// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts.
|
||||
/// This is lazily created. This is intentionally not serialized.
|
||||
llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts;
|
||||
llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*> ObjCLayouts;
|
||||
|
||||
llvm::DenseMap<unsigned, FixedWidthIntType*> SignedFixedWidthIntTypes;
|
||||
llvm::DenseMap<unsigned, FixedWidthIntType*> UnsignedFixedWidthIntTypes;
|
||||
|
||||
/// BuiltinVaListType - built-in va list type.
|
||||
/// This is initially null and set by Sema::LazilyCreateBuiltin when
|
||||
/// a builtin that takes a valist is encountered.
|
||||
QualType BuiltinVaListType;
|
||||
|
||||
/// ObjCIdType - a pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCIdType;
|
||||
const RecordType *IdStructType;
|
||||
|
||||
/// ObjCSelType - another pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCSelType;
|
||||
const RecordType *SelStructType;
|
||||
|
||||
/// ObjCProtoType - another pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCProtoType;
|
||||
const RecordType *ProtoStructType;
|
||||
|
||||
/// ObjCClassType - another pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCClassType;
|
||||
const RecordType *ClassStructType;
|
||||
|
||||
QualType ObjCConstantStringType;
|
||||
RecordDecl *CFConstantStringTypeDecl;
|
||||
|
||||
RecordDecl *ObjCFastEnumerationStateTypeDecl;
|
||||
|
||||
TranslationUnitDecl *TUDecl;
|
||||
|
||||
/// SourceMgr - The associated SourceManager object.
|
||||
SourceManager &SourceMgr;
|
||||
|
||||
/// LangOpts - The language options used to create the AST associated with
|
||||
/// this ASTContext object.
|
||||
LangOptions LangOpts;
|
||||
|
||||
/// MallocAlloc/BumpAlloc - The allocator objects used to create AST objects.
|
||||
bool FreeMemory;
|
||||
llvm::MallocAllocator MallocAlloc;
|
||||
llvm::BumpPtrAllocator BumpAlloc;
|
||||
public:
|
||||
TargetInfo &Target;
|
||||
IdentifierTable &Idents;
|
||||
SelectorTable &Selectors;
|
||||
DeclarationNameTable DeclarationNames;
|
||||
llvm::OwningPtr<ExternalASTSource> ExternalSource;
|
||||
clang::PrintingPolicy PrintingPolicy;
|
||||
|
||||
SourceManager& getSourceManager() { return SourceMgr; }
|
||||
const SourceManager& getSourceManager() const { return SourceMgr; }
|
||||
void *Allocate(unsigned Size, unsigned Align = 8) {
|
||||
return FreeMemory ? MallocAlloc.Allocate(Size, Align) :
|
||||
BumpAlloc.Allocate(Size, Align);
|
||||
}
|
||||
void Deallocate(void *Ptr) {
|
||||
if (FreeMemory)
|
||||
MallocAlloc.Deallocate(Ptr);
|
||||
}
|
||||
const LangOptions& getLangOptions() const { return LangOpts; }
|
||||
|
||||
FullSourceLoc getFullLoc(SourceLocation Loc) const {
|
||||
return FullSourceLoc(Loc,SourceMgr);
|
||||
}
|
||||
|
||||
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
|
||||
|
||||
Builtin::Context BuiltinInfo;
|
||||
|
||||
// Builtin Types.
|
||||
QualType VoidTy;
|
||||
QualType BoolTy;
|
||||
QualType CharTy;
|
||||
QualType WCharTy; // [C++ 3.9.1p5], integer type in C99.
|
||||
QualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty;
|
||||
QualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy;
|
||||
QualType UnsignedLongLongTy, UnsignedInt128Ty;
|
||||
QualType FloatTy, DoubleTy, LongDoubleTy;
|
||||
QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
||||
QualType VoidPtrTy, NullPtrTy;
|
||||
QualType OverloadTy;
|
||||
QualType DependentTy;
|
||||
|
||||
ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t,
|
||||
IdentifierTable &idents, SelectorTable &sels,
|
||||
bool FreeMemory = true, unsigned size_reserve=0,
|
||||
bool InitializeBuiltins = true);
|
||||
|
||||
~ASTContext();
|
||||
|
||||
/// \brief Initialize builtins.
|
||||
///
|
||||
/// Typically, this routine will be called automatically by the
|
||||
/// constructor. However, in certain cases (e.g., when there is a
|
||||
/// PCH file to be loaded), the constructor does not perform
|
||||
/// initialization for builtins. This routine can be called to
|
||||
/// perform the initialization.
|
||||
void InitializeBuiltins(IdentifierTable &idents);
|
||||
|
||||
/// \brief Attach an external AST source to the AST context.
|
||||
///
|
||||
/// The external AST source provides the ability to load parts of
|
||||
/// the abstract syntax tree as needed from some external storage,
|
||||
/// e.g., a precompiled header.
|
||||
void setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source);
|
||||
|
||||
/// \brief Retrieve a pointer to the external AST source associated
|
||||
/// with this AST context, if any.
|
||||
ExternalASTSource *getExternalSource() const { return ExternalSource.get(); }
|
||||
|
||||
void PrintStats() const;
|
||||
const std::vector<Type*>& getTypes() const { return Types; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Constructors
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// getAddSpaceQualType - Return the uniqued reference to the type for an
|
||||
/// address space qualified type with the specified type and address space.
|
||||
/// The resulting type has a union of the qualifiers from T and the address
|
||||
/// space. If T already has an address space specifier, it is silently
|
||||
/// replaced.
|
||||
QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace);
|
||||
|
||||
/// getObjCGCQualType - Returns the uniqued reference to the type for an
|
||||
/// objc gc qualified type. The retulting type has a union of the qualifiers
|
||||
/// from T and the gc attribute.
|
||||
QualType getObjCGCQualType(QualType T, QualType::GCAttrTypes gcAttr);
|
||||
|
||||
/// getComplexType - Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType getComplexType(QualType T);
|
||||
|
||||
/// getPointerType - Return the uniqued reference to the type for a pointer to
|
||||
/// the specified type.
|
||||
QualType getPointerType(QualType T);
|
||||
|
||||
/// getBlockPointerType - Return the uniqued reference to the type for a block
|
||||
/// of the specified type.
|
||||
QualType getBlockPointerType(QualType T);
|
||||
|
||||
/// getLValueReferenceType - Return the uniqued reference to the type for an
|
||||
/// lvalue reference to the specified type.
|
||||
QualType getLValueReferenceType(QualType T);
|
||||
|
||||
/// getRValueReferenceType - Return the uniqued reference to the type for an
|
||||
/// rvalue reference to the specified type.
|
||||
QualType getRValueReferenceType(QualType T);
|
||||
|
||||
/// getMemberPointerType - Return the uniqued reference to the type for a
|
||||
/// member pointer to the specified type in the specified class. The class
|
||||
/// is a Type because it could be a dependent name.
|
||||
QualType getMemberPointerType(QualType T, const Type *Cls);
|
||||
|
||||
/// getVariableArrayType - Returns a non-unique reference to the type for a
|
||||
/// variable array of the specified element type.
|
||||
QualType getVariableArrayType(QualType EltTy, Expr *NumElts,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals);
|
||||
|
||||
/// getDependentSizedArrayType - Returns a non-unique reference to
|
||||
/// the type for a dependently-sized array of the specified element
|
||||
/// type. FIXME: We will need these to be uniqued, or at least
|
||||
/// comparable, at some point.
|
||||
QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals);
|
||||
|
||||
/// getIncompleteArrayType - Returns a unique reference to the type for a
|
||||
/// incomplete array of the specified element type.
|
||||
QualType getIncompleteArrayType(QualType EltTy,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals);
|
||||
|
||||
/// getConstantArrayType - Return the unique reference to the type for a
|
||||
/// constant array of the specified element type.
|
||||
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals);
|
||||
|
||||
/// getVectorType - Return the unique reference to a vector type of
|
||||
/// the specified element type and size. VectorType must be a built-in type.
|
||||
QualType getVectorType(QualType VectorType, unsigned NumElts);
|
||||
|
||||
/// getExtVectorType - Return the unique reference to an extended vector type
|
||||
/// of the specified element type and size. VectorType must be a built-in
|
||||
/// type.
|
||||
QualType getExtVectorType(QualType VectorType, unsigned NumElts);
|
||||
|
||||
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
|
||||
///
|
||||
QualType getFunctionNoProtoType(QualType ResultTy);
|
||||
|
||||
/// getFunctionType - Return a normal function type with a typed argument
|
||||
/// list. isVariadic indicates whether the argument list includes '...'.
|
||||
QualType getFunctionType(QualType ResultTy, const QualType *ArgArray,
|
||||
unsigned NumArgs, bool isVariadic,
|
||||
unsigned TypeQuals, bool hasExceptionSpec = false,
|
||||
bool hasAnyExceptionSpec = false,
|
||||
unsigned NumExs = 0, const QualType *ExArray = 0);
|
||||
|
||||
/// getTypeDeclType - Return the unique reference to the type for
|
||||
/// the specified type declaration.
|
||||
QualType getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl=0);
|
||||
|
||||
/// getTypedefType - Return the unique reference to the type for the
|
||||
/// specified typename decl.
|
||||
QualType getTypedefType(TypedefDecl *Decl);
|
||||
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl);
|
||||
|
||||
QualType getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
||||
IdentifierInfo *Name = 0);
|
||||
|
||||
QualType getTemplateSpecializationType(TemplateName T,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
QualType Canon = QualType());
|
||||
|
||||
QualType getQualifiedNameType(NestedNameSpecifier *NNS,
|
||||
QualType NamedType);
|
||||
QualType getTypenameType(NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name,
|
||||
QualType Canon = QualType());
|
||||
QualType getTypenameType(NestedNameSpecifier *NNS,
|
||||
const TemplateSpecializationType *TemplateId,
|
||||
QualType Canon = QualType());
|
||||
|
||||
/// getObjCQualifiedInterfaceType - Return a
|
||||
/// ObjCQualifiedInterfaceType type for the given interface decl and
|
||||
/// the conforming protocol list.
|
||||
QualType getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl,
|
||||
ObjCProtocolDecl **ProtocolList,
|
||||
unsigned NumProtocols);
|
||||
|
||||
/// getObjCQualifiedIdType - Return an ObjCQualifiedIdType for a
|
||||
/// given 'id' and conforming protocol list.
|
||||
QualType getObjCQualifiedIdType(ObjCProtocolDecl **ProtocolList,
|
||||
unsigned NumProtocols);
|
||||
|
||||
|
||||
/// getTypeOfType - GCC extension.
|
||||
QualType getTypeOfExprType(Expr *e);
|
||||
QualType getTypeOfType(QualType t);
|
||||
|
||||
/// getTagDeclType - Return the unique reference to the type for the
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType getTagDeclType(TagDecl *Decl);
|
||||
|
||||
/// getSizeType - Return the unique type for "size_t" (C99 7.17), defined
|
||||
/// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4).
|
||||
QualType getSizeType() const;
|
||||
|
||||
/// getWCharType - In C++, this returns the unique wchar_t type. In C99, this
|
||||
/// returns a type compatible with the type defined in <stddef.h> as defined
|
||||
/// by the target.
|
||||
QualType getWCharType() const { return WCharTy; }
|
||||
|
||||
/// getSignedWCharType - Return the type of "signed wchar_t".
|
||||
/// Used when in C++, as a GCC extension.
|
||||
QualType getSignedWCharType() const;
|
||||
|
||||
/// getUnsignedWCharType - Return the type of "unsigned wchar_t".
|
||||
/// Used when in C++, as a GCC extension.
|
||||
QualType getUnsignedWCharType() const;
|
||||
|
||||
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
|
||||
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
|
||||
QualType getPointerDiffType() const;
|
||||
|
||||
// getCFConstantStringType - Return the C structure type used to represent
|
||||
// constant CFStrings.
|
||||
QualType getCFConstantStringType();
|
||||
|
||||
/// Get the structure type used to representation CFStrings, or NULL
|
||||
/// if it hasn't yet been built.
|
||||
QualType getRawCFConstantStringType() {
|
||||
if (CFConstantStringTypeDecl)
|
||||
return getTagDeclType(CFConstantStringTypeDecl);
|
||||
return QualType();
|
||||
}
|
||||
void setCFConstantStringType(QualType T);
|
||||
|
||||
// This setter/getter represents the ObjC type for an NSConstantString.
|
||||
void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl);
|
||||
QualType getObjCConstantStringInterface() const {
|
||||
return ObjCConstantStringType;
|
||||
}
|
||||
|
||||
//// This gets the struct used to keep track of fast enumerations.
|
||||
QualType getObjCFastEnumerationStateType();
|
||||
|
||||
/// Get the ObjCFastEnumerationState type, or NULL if it hasn't yet
|
||||
/// been built.
|
||||
QualType getRawObjCFastEnumerationStateType() {
|
||||
if (ObjCFastEnumerationStateTypeDecl)
|
||||
return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
|
||||
return QualType();
|
||||
}
|
||||
|
||||
void setObjCFastEnumerationStateType(QualType T);
|
||||
|
||||
/// getObjCEncodingForType - Emit the ObjC type encoding for the
|
||||
/// given type into \arg S. If \arg NameFields is specified then
|
||||
/// record field names are also encoded.
|
||||
void getObjCEncodingForType(QualType t, std::string &S,
|
||||
const FieldDecl *Field=0);
|
||||
|
||||
void getLegacyIntegralTypeEncoding(QualType &t) const;
|
||||
|
||||
// Put the string version of type qualifiers into S.
|
||||
void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
|
||||
std::string &S) const;
|
||||
|
||||
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
|
||||
/// declaration.
|
||||
void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S);
|
||||
|
||||
/// getObjCEncodingForPropertyDecl - Return the encoded type for
|
||||
/// this method declaration. If non-NULL, Container must be either
|
||||
/// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should
|
||||
/// only be NULL when getting encodings for protocol properties.
|
||||
void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
|
||||
const Decl *Container,
|
||||
std::string &S);
|
||||
|
||||
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
|
||||
/// purpose.
|
||||
int getObjCEncodingTypeSize(QualType t);
|
||||
|
||||
/// This setter/getter represents the ObjC 'id' type. It is setup lazily, by
|
||||
/// Sema. id is always a (typedef for a) pointer type, a pointer to a struct.
|
||||
QualType getObjCIdType() const { return ObjCIdType; }
|
||||
void setObjCIdType(QualType T);
|
||||
|
||||
void setObjCSelType(QualType T);
|
||||
QualType getObjCSelType() const { return ObjCSelType; }
|
||||
|
||||
void setObjCProtoType(QualType QT);
|
||||
QualType getObjCProtoType() const { return ObjCProtoType; }
|
||||
|
||||
/// This setter/getter repreents the ObjC 'Class' type. It is setup lazily, by
|
||||
/// Sema. 'Class' is always a (typedef for a) pointer type, a pointer to a
|
||||
/// struct.
|
||||
QualType getObjCClassType() const { return ObjCClassType; }
|
||||
void setObjCClassType(QualType T);
|
||||
|
||||
void setBuiltinVaListType(QualType T);
|
||||
QualType getBuiltinVaListType() const { return BuiltinVaListType; }
|
||||
|
||||
QualType getFixedWidthIntType(unsigned Width, bool Signed);
|
||||
|
||||
TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
|
||||
bool TemplateKeyword,
|
||||
TemplateDecl *Template);
|
||||
|
||||
TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name);
|
||||
|
||||
private:
|
||||
QualType getFromTargetType(unsigned Type) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Predicates.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
/// isObjCObjectPointerType - Returns true if type is an Objective-C pointer
|
||||
/// to an object type. This includes "id" and "Class" (two 'special' pointers
|
||||
/// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
|
||||
/// ID type).
|
||||
bool isObjCObjectPointerType(QualType Ty) const;
|
||||
|
||||
/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
|
||||
/// garbage collection attribute.
|
||||
///
|
||||
QualType::GCAttrTypes getObjCGCAttrKind(const QualType &Ty) const;
|
||||
|
||||
/// isObjCNSObjectType - Return true if this is an NSObject object with
|
||||
/// its NSObject attribute set.
|
||||
bool isObjCNSObjectType(QualType Ty) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Sizing and Analysis
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified
|
||||
/// scalar floating point type.
|
||||
const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const;
|
||||
|
||||
/// getTypeInfo - Get the size and alignment of the specified complete type in
|
||||
/// bits.
|
||||
std::pair<uint64_t, unsigned> getTypeInfo(const Type *T);
|
||||
std::pair<uint64_t, unsigned> getTypeInfo(QualType T) {
|
||||
return getTypeInfo(T.getTypePtr());
|
||||
}
|
||||
|
||||
/// getTypeSize - Return the size of the specified type, in bits. This method
|
||||
/// does not work on incomplete types.
|
||||
uint64_t getTypeSize(QualType T) {
|
||||
return getTypeInfo(T).first;
|
||||
}
|
||||
uint64_t getTypeSize(const Type *T) {
|
||||
return getTypeInfo(T).first;
|
||||
}
|
||||
|
||||
/// getTypeAlign - Return the ABI-specified alignment of a type, in bits.
|
||||
/// This method does not work on incomplete types.
|
||||
unsigned getTypeAlign(QualType T) {
|
||||
return getTypeInfo(T).second;
|
||||
}
|
||||
unsigned getTypeAlign(const Type *T) {
|
||||
return getTypeInfo(T).second;
|
||||
}
|
||||
|
||||
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
|
||||
/// type for the current target in bits. This can be different than the ABI
|
||||
/// alignment in cases where it is beneficial for performance to overalign
|
||||
/// a data type.
|
||||
unsigned getPreferredTypeAlign(const Type *T);
|
||||
|
||||
/// getDeclAlignInBytes - Return the alignment of the specified decl
|
||||
/// that should be returned by __alignof(). Note that bitfields do
|
||||
/// not have a valid alignment, so this method will assert on them.
|
||||
unsigned getDeclAlignInBytes(const Decl *D);
|
||||
|
||||
/// getASTRecordLayout - Get or compute information about the layout of the
|
||||
/// specified record (struct/union/class), which indicates its size and field
|
||||
/// position information.
|
||||
const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D);
|
||||
|
||||
/// getASTObjCInterfaceLayout - Get or compute information about the
|
||||
/// layout of the specified Objective-C interface.
|
||||
const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D);
|
||||
|
||||
/// getASTObjCImplementationLayout - Get or compute information about
|
||||
/// the layout of the specified Objective-C implementation. This may
|
||||
/// differ from the interface if synthesized ivars are present.
|
||||
const ASTRecordLayout &
|
||||
getASTObjCImplementationLayout(const ObjCImplementationDecl *D);
|
||||
|
||||
void CollectObjCIvars(const ObjCInterfaceDecl *OI,
|
||||
llvm::SmallVectorImpl<FieldDecl*> &Fields);
|
||||
|
||||
void CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
|
||||
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
|
||||
void CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
|
||||
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Operators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// getCanonicalType - Return the canonical (structural) type corresponding to
|
||||
/// the specified potentially non-canonical type. The non-canonical version
|
||||
/// of a type may have many "decorated" versions of types. Decorators can
|
||||
/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
|
||||
/// to be free of any of these, allowing two canonical types to be compared
|
||||
/// for exact equality with a simple pointer comparison.
|
||||
QualType getCanonicalType(QualType T);
|
||||
const Type *getCanonicalType(const Type *T) {
|
||||
return T->getCanonicalTypeInternal().getTypePtr();
|
||||
}
|
||||
|
||||
/// \brief Determine whether the given types are equivalent.
|
||||
bool hasSameType(QualType T1, QualType T2) {
|
||||
return getCanonicalType(T1) == getCanonicalType(T2);
|
||||
}
|
||||
|
||||
/// \brief Determine whether the given types are equivalent after
|
||||
/// cvr-qualifiers have been removed.
|
||||
bool hasSameUnqualifiedType(QualType T1, QualType T2) {
|
||||
T1 = getCanonicalType(T1);
|
||||
T2 = getCanonicalType(T2);
|
||||
return T1.getUnqualifiedType() == T2.getUnqualifiedType();
|
||||
}
|
||||
|
||||
/// \brief Retrieves the "canonical" declaration of the given declaration.
|
||||
Decl *getCanonicalDecl(Decl *D);
|
||||
|
||||
/// \brief Retrieves the "canonical" declaration of the given tag
|
||||
/// declaration.
|
||||
///
|
||||
/// The canonical declaration for the given tag declaration is
|
||||
/// either the definition of the tag (if it is a complete type) or
|
||||
/// the first declaration of that tag.
|
||||
TagDecl *getCanonicalDecl(TagDecl *Tag) {
|
||||
return cast<TagDecl>(getCanonicalDecl((Decl *)Tag));
|
||||
}
|
||||
|
||||
/// \brief Retrieves the "canonical" declaration of
|
||||
|
||||
/// \brief Retrieves the "canonical" nested name specifier for a
|
||||
/// given nested name specifier.
|
||||
///
|
||||
/// The canonical nested name specifier is a nested name specifier
|
||||
/// that uniquely identifies a type or namespace within the type
|
||||
/// system. For example, given:
|
||||
///
|
||||
/// \code
|
||||
/// namespace N {
|
||||
/// struct S {
|
||||
/// template<typename T> struct X { typename T* type; };
|
||||
/// };
|
||||
/// }
|
||||
///
|
||||
/// template<typename T> struct Y {
|
||||
/// typename N::S::X<T>::type member;
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// Here, the nested-name-specifier for N::S::X<T>:: will be
|
||||
/// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined
|
||||
/// by declarations in the type system and the canonical type for
|
||||
/// the template type parameter 'T' is template-param-0-0.
|
||||
NestedNameSpecifier *
|
||||
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS);
|
||||
|
||||
/// \brief Retrieves the "canonical" template name that refers to a
|
||||
/// given template.
|
||||
///
|
||||
/// The canonical template name is the simplest expression that can
|
||||
/// be used to refer to a given template. For most templates, this
|
||||
/// expression is just the template declaration itself. For example,
|
||||
/// the template std::vector can be referred to via a variety of
|
||||
/// names---std::vector, ::std::vector, vector (if vector is in
|
||||
/// scope), etc.---but all of these names map down to the same
|
||||
/// TemplateDecl, which is used to form the canonical template name.
|
||||
///
|
||||
/// Dependent template names are more interesting. Here, the
|
||||
/// template name could be something like T::template apply or
|
||||
/// std::allocator<T>::template rebind, where the nested name
|
||||
/// specifier itself is dependent. In this case, the canonical
|
||||
/// template name uses the shortest form of the dependent
|
||||
/// nested-name-specifier, which itself contains all canonical
|
||||
/// types, values, and templates.
|
||||
TemplateName getCanonicalTemplateName(TemplateName Name);
|
||||
|
||||
/// Type Query functions. If the type is an instance of the specified class,
|
||||
/// return the Type pointer for the underlying maximally pretty type. This
|
||||
/// is a member of ASTContext because this may need to do some amount of
|
||||
/// canonicalization, e.g. to move type qualifiers into the element type.
|
||||
const ArrayType *getAsArrayType(QualType T);
|
||||
const ConstantArrayType *getAsConstantArrayType(QualType T) {
|
||||
return dyn_cast_or_null<ConstantArrayType>(getAsArrayType(T));
|
||||
}
|
||||
const VariableArrayType *getAsVariableArrayType(QualType T) {
|
||||
return dyn_cast_or_null<VariableArrayType>(getAsArrayType(T));
|
||||
}
|
||||
const IncompleteArrayType *getAsIncompleteArrayType(QualType T) {
|
||||
return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T));
|
||||
}
|
||||
|
||||
/// getBaseElementType - Returns the innermost element type of a variable
|
||||
/// length array type. For example, will return "int" for int[m][n]
|
||||
QualType getBaseElementType(const VariableArrayType *VAT);
|
||||
|
||||
/// getArrayDecayedType - Return the properly qualified result of decaying the
|
||||
/// specified array type to a pointer. This operation is non-trivial when
|
||||
/// handling typedefs etc. The canonical type of "T" must be an array type,
|
||||
/// this returns a pointer to a properly qualified element of the array.
|
||||
///
|
||||
/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
|
||||
QualType getArrayDecayedType(QualType T);
|
||||
|
||||
/// getIntegerTypeOrder - Returns the highest ranked integer type:
|
||||
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
|
||||
/// LHS < RHS, return -1.
|
||||
int getIntegerTypeOrder(QualType LHS, QualType RHS);
|
||||
|
||||
/// getFloatingTypeOrder - Compare the rank of the two specified floating
|
||||
/// point types, ignoring the domain of the type (i.e. 'double' ==
|
||||
/// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
|
||||
/// LHS < RHS, return -1.
|
||||
int getFloatingTypeOrder(QualType LHS, QualType RHS);
|
||||
|
||||
/// getFloatingTypeOfSizeWithinDomain - Returns a real floating
|
||||
/// point or a complex type (based on typeDomain/typeSize).
|
||||
/// 'typeDomain' is a real floating point or complex type.
|
||||
/// 'typeSize' is a real floating point or complex type.
|
||||
QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize,
|
||||
QualType typeDomain) const;
|
||||
|
||||
private:
|
||||
// Helper for integer ordering
|
||||
unsigned getIntegerRank(Type* T);
|
||||
|
||||
public:
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Compatibility Predicates
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// Compatibility predicates used to check assignment expressions.
|
||||
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
|
||||
bool typesAreBlockCompatible(QualType lhs, QualType rhs);
|
||||
|
||||
bool isObjCIdType(QualType T) const {
|
||||
return T == ObjCIdType;
|
||||
}
|
||||
bool isObjCIdStructType(QualType T) const {
|
||||
if (!IdStructType) // ObjC isn't enabled
|
||||
return false;
|
||||
return T->getAsStructureType() == IdStructType;
|
||||
}
|
||||
bool isObjCClassType(QualType T) const {
|
||||
return T == ObjCClassType;
|
||||
}
|
||||
bool isObjCClassStructType(QualType T) const {
|
||||
if (!ClassStructType) // ObjC isn't enabled
|
||||
return false;
|
||||
return T->getAsStructureType() == ClassStructType;
|
||||
}
|
||||
bool isObjCSelType(QualType T) const {
|
||||
assert(SelStructType && "isObjCSelType used before 'SEL' type is built");
|
||||
return T->getAsStructureType() == SelStructType;
|
||||
}
|
||||
|
||||
// Check the safety of assignment from LHS to RHS
|
||||
bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
|
||||
const ObjCInterfaceType *RHS);
|
||||
bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
|
||||
|
||||
// Functions for calculating composite types
|
||||
QualType mergeTypes(QualType, QualType);
|
||||
QualType mergeFunctionTypes(QualType, QualType);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Integer Predicates
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
// The width of an integer, as defined in C99 6.2.6.2. This is the number
|
||||
// of bits in an integer type excluding any padding bits.
|
||||
unsigned getIntWidth(QualType T);
|
||||
|
||||
// Per C99 6.2.5p6, for every signed integer type, there is a corresponding
|
||||
// unsigned integer type. This method takes a signed type, and returns the
|
||||
// corresponding unsigned integer type.
|
||||
QualType getCorrespondingUnsignedType(QualType T);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Iterators.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
typedef std::vector<Type*>::iterator type_iterator;
|
||||
typedef std::vector<Type*>::const_iterator const_type_iterator;
|
||||
|
||||
type_iterator types_begin() { return Types.begin(); }
|
||||
type_iterator types_end() { return Types.end(); }
|
||||
const_type_iterator types_begin() const { return Types.begin(); }
|
||||
const_type_iterator types_end() const { return Types.end(); }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Integer Values
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// MakeIntValue - Make an APSInt of the appropriate width and
|
||||
/// signedness for the given \arg Value and integer \arg Type.
|
||||
llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) {
|
||||
llvm::APSInt Res(getIntWidth(Type), !Type->isSignedIntegerType());
|
||||
Res = Value;
|
||||
return Res;
|
||||
}
|
||||
|
||||
private:
|
||||
ASTContext(const ASTContext&); // DO NOT IMPLEMENT
|
||||
void operator=(const ASTContext&); // DO NOT IMPLEMENT
|
||||
|
||||
void InitBuiltinTypes();
|
||||
void InitBuiltinType(QualType &R, BuiltinType::Kind K);
|
||||
|
||||
// Return the ObjC type encoding for a given type.
|
||||
void getObjCEncodingForTypeImpl(QualType t, std::string &S,
|
||||
bool ExpandPointedToStructures,
|
||||
bool ExpandStructures,
|
||||
const FieldDecl *Field,
|
||||
bool OutermostType = false,
|
||||
bool EncodingProperty = false);
|
||||
|
||||
const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D,
|
||||
const ObjCImplementationDecl *Impl);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
// operator new and delete aren't allowed inside namespaces.
|
||||
// The throw specifications are mandated by the standard.
|
||||
/// @brief Placement new for using the ASTContext's allocator.
|
||||
///
|
||||
/// This placement form of operator new uses the ASTContext's allocator for
|
||||
/// obtaining memory. It is a non-throwing new, which means that it returns
|
||||
/// null on error. (If that is what the allocator does. The current does, so if
|
||||
/// this ever changes, this operator will have to be changed, too.)
|
||||
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
|
||||
/// @code
|
||||
/// // Default alignment (16)
|
||||
/// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments);
|
||||
/// // Specific alignment
|
||||
/// IntegerLiteral *Ex2 = new (Context, 8) IntegerLiteral(arguments);
|
||||
/// @endcode
|
||||
/// Please note that you cannot use delete on the pointer; it must be
|
||||
/// deallocated using an explicit destructor call followed by
|
||||
/// @c Context.Deallocate(Ptr).
|
||||
///
|
||||
/// @param Bytes The number of bytes to allocate. Calculated by the compiler.
|
||||
/// @param C The ASTContext that provides the allocator.
|
||||
/// @param Alignment The alignment of the allocated memory (if the underlying
|
||||
/// allocator supports it).
|
||||
/// @return The allocated memory. Could be NULL.
|
||||
inline void *operator new(size_t Bytes, clang::ASTContext &C,
|
||||
size_t Alignment) throw () {
|
||||
return C.Allocate(Bytes, Alignment);
|
||||
}
|
||||
/// @brief Placement delete companion to the new above.
|
||||
///
|
||||
/// This operator is just a companion to the new above. There is no way of
|
||||
/// invoking it directly; see the new operator for more details. This operator
|
||||
/// is called implicitly by the compiler if a placement new expression using
|
||||
/// the ASTContext throws in the object constructor.
|
||||
inline void operator delete(void *Ptr, clang::ASTContext &C, size_t)
|
||||
throw () {
|
||||
C.Deallocate(Ptr);
|
||||
}
|
||||
|
||||
/// This placement form of operator new[] uses the ASTContext's allocator for
|
||||
/// obtaining memory. It is a non-throwing new[], which means that it returns
|
||||
/// null on error.
|
||||
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
|
||||
/// @code
|
||||
/// // Default alignment (16)
|
||||
/// char *data = new (Context) char[10];
|
||||
/// // Specific alignment
|
||||
/// char *data = new (Context, 8) char[10];
|
||||
/// @endcode
|
||||
/// Please note that you cannot use delete on the pointer; it must be
|
||||
/// deallocated using an explicit destructor call followed by
|
||||
/// @c Context.Deallocate(Ptr).
|
||||
///
|
||||
/// @param Bytes The number of bytes to allocate. Calculated by the compiler.
|
||||
/// @param C The ASTContext that provides the allocator.
|
||||
/// @param Alignment The alignment of the allocated memory (if the underlying
|
||||
/// allocator supports it).
|
||||
/// @return The allocated memory. Could be NULL.
|
||||
inline void *operator new[](size_t Bytes, clang::ASTContext& C,
|
||||
size_t Alignment = 16) throw () {
|
||||
return C.Allocate(Bytes, Alignment);
|
||||
}
|
||||
|
||||
/// @brief Placement delete[] companion to the new[] above.
|
||||
///
|
||||
/// This operator is just a companion to the new[] above. There is no way of
|
||||
/// invoking it directly; see the new[] operator for more details. This operator
|
||||
/// is called implicitly by the compiler if a placement new[] expression using
|
||||
/// the ASTContext throws in the object constructor.
|
||||
inline void operator delete[](void *Ptr, clang::ASTContext &C) throw () {
|
||||
C.Deallocate(Ptr);
|
||||
}
|
||||
|
||||
#endif
|
27
include/clang/AST/ASTDiagnostic.h
Normal file
27
include/clang/AST/ASTDiagnostic.h
Normal file
@ -0,0 +1,27 @@
|
||||
//===--- DiagnosticAST.h - Diagnostics for the AST library ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_DIAGNOSTICAST_H
|
||||
#define LLVM_CLANG_DIAGNOSTICAST_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
|
||||
#define ASTSTART
|
||||
#include "clang/Basic/DiagnosticASTKinds.inc"
|
||||
#undef DIAG
|
||||
NUM_BUILTIN_AST_DIAGNOSTICS
|
||||
};
|
||||
} // end namespace diag
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
506
include/clang/AST/Attr.h
Normal file
506
include/clang/AST/Attr.h
Normal file
@ -0,0 +1,506 @@
|
||||
//===--- Attr.h - Classes for representing expressions ----------*- 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 Attr interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ATTR_H
|
||||
#define LLVM_CLANG_AST_ATTR_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
}
|
||||
|
||||
|
||||
// Defined in ASTContext.cpp
|
||||
void *operator new(size_t Bytes, clang::ASTContext &C,
|
||||
size_t Alignment = 16) throw ();
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// Attr - This represents one attribute.
|
||||
class Attr {
|
||||
public:
|
||||
enum Kind {
|
||||
Alias,
|
||||
Aligned,
|
||||
AlwaysInline,
|
||||
AnalyzerNoReturn, // Clang-specific.
|
||||
Annotate,
|
||||
AsmLabel, // Represent GCC asm label extension.
|
||||
Blocks,
|
||||
Cleanup,
|
||||
Const,
|
||||
Constructor,
|
||||
DLLExport,
|
||||
DLLImport,
|
||||
Deprecated,
|
||||
Destructor,
|
||||
FastCall,
|
||||
Format,
|
||||
FormatArg,
|
||||
GNUInline,
|
||||
IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with
|
||||
NoReturn,
|
||||
NoThrow,
|
||||
Nodebug,
|
||||
Noinline,
|
||||
NonNull,
|
||||
ObjCException,
|
||||
ObjCNSObject,
|
||||
CFReturnsRetained, // Clang/Checker-specific.
|
||||
NSReturnsRetained, // Clang/Checker-specific.
|
||||
Overloadable, // Clang-specific
|
||||
Packed,
|
||||
Pure,
|
||||
Regparm,
|
||||
Section,
|
||||
Sentinel,
|
||||
StdCall,
|
||||
TransparentUnion,
|
||||
Unavailable,
|
||||
Unused,
|
||||
Used,
|
||||
Visibility,
|
||||
WarnUnusedResult,
|
||||
Weak,
|
||||
WeakImport
|
||||
};
|
||||
|
||||
private:
|
||||
Attr *Next;
|
||||
Kind AttrKind;
|
||||
bool Inherited : 1;
|
||||
|
||||
protected:
|
||||
void* operator new(size_t bytes) throw() {
|
||||
assert(0 && "Attrs cannot be allocated with regular 'new'.");
|
||||
return 0;
|
||||
}
|
||||
void operator delete(void* data) throw() {
|
||||
assert(0 && "Attrs cannot be released with regular 'delete'.");
|
||||
}
|
||||
|
||||
protected:
|
||||
Attr(Kind AK) : Next(0), AttrKind(AK), Inherited(false) {}
|
||||
virtual ~Attr() {
|
||||
assert(Next == 0 && "Destroy didn't work");
|
||||
}
|
||||
public:
|
||||
|
||||
void Destroy(ASTContext &C);
|
||||
|
||||
/// \brief Whether this attribute should be merged to new
|
||||
/// declarations.
|
||||
virtual bool isMerged() const { return true; }
|
||||
|
||||
Kind getKind() const { return AttrKind; }
|
||||
|
||||
Attr *getNext() { return Next; }
|
||||
const Attr *getNext() const { return Next; }
|
||||
void setNext(Attr *next) { Next = next; }
|
||||
|
||||
bool isInherited() const { return Inherited; }
|
||||
void setInherited(bool value) { Inherited = value; }
|
||||
|
||||
void addAttr(Attr *attr) {
|
||||
assert((attr != 0) && "addAttr(): attr is null");
|
||||
|
||||
// FIXME: This doesn't preserve the order in any way.
|
||||
attr->Next = Next;
|
||||
Next = attr;
|
||||
}
|
||||
|
||||
// Clone this attribute.
|
||||
virtual Attr* clone(ASTContext &C) const = 0;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *) { return true; }
|
||||
};
|
||||
|
||||
#define DEF_SIMPLE_ATTR(ATTR) \
|
||||
class ATTR##Attr : public Attr { \
|
||||
public: \
|
||||
ATTR##Attr() : Attr(ATTR) {} \
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) ATTR##Attr; }\
|
||||
static bool classof(const Attr *A) { return A->getKind() == ATTR; } \
|
||||
static bool classof(const ATTR##Attr *A) { return true; } \
|
||||
}
|
||||
|
||||
class PackedAttr : public Attr {
|
||||
unsigned Alignment;
|
||||
|
||||
public:
|
||||
PackedAttr(unsigned alignment) : Attr(Packed), Alignment(alignment) {}
|
||||
|
||||
/// getAlignment - The specified alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const {
|
||||
return ::new (C) PackedAttr(Alignment);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Packed;
|
||||
}
|
||||
static bool classof(const PackedAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class AlignedAttr : public Attr {
|
||||
unsigned Alignment;
|
||||
public:
|
||||
AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {}
|
||||
|
||||
/// getAlignment - The specified alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Aligned;
|
||||
}
|
||||
static bool classof(const AlignedAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class AnnotateAttr : public Attr {
|
||||
std::string Annotation;
|
||||
public:
|
||||
AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {}
|
||||
|
||||
const std::string& getAnnotation() const { return Annotation; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const { return ::new (C) AnnotateAttr(Annotation); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Annotate;
|
||||
}
|
||||
static bool classof(const AnnotateAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class AsmLabelAttr : public Attr {
|
||||
std::string Label;
|
||||
public:
|
||||
AsmLabelAttr(const std::string &L) : Attr(AsmLabel), Label(L) {}
|
||||
|
||||
const std::string& getLabel() const { return Label; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const { return ::new (C) AsmLabelAttr(Label); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == AsmLabel;
|
||||
}
|
||||
static bool classof(const AsmLabelAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(AlwaysInline);
|
||||
|
||||
class AliasAttr : public Attr {
|
||||
std::string Aliasee;
|
||||
public:
|
||||
AliasAttr(const std::string &aliasee) : Attr(Alias), Aliasee(aliasee) {}
|
||||
|
||||
const std::string& getAliasee() const { return Aliasee; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) AliasAttr(Aliasee); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Alias; }
|
||||
static bool classof(const AliasAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class ConstructorAttr : public Attr {
|
||||
int priority;
|
||||
public:
|
||||
ConstructorAttr(int p) : Attr(Constructor), priority(p) {}
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) ConstructorAttr(priority); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Constructor; }
|
||||
static bool classof(const ConstructorAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class DestructorAttr : public Attr {
|
||||
int priority;
|
||||
public:
|
||||
DestructorAttr(int p) : Attr(Destructor), priority(p) {}
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) DestructorAttr(priority); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Destructor; }
|
||||
static bool classof(const DestructorAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class GNUInlineAttr : public Attr {
|
||||
public:
|
||||
GNUInlineAttr() : Attr(GNUInline) {}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) GNUInlineAttr; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == GNUInline;
|
||||
}
|
||||
static bool classof(const GNUInlineAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class IBOutletAttr : public Attr {
|
||||
public:
|
||||
IBOutletAttr() : Attr(IBOutletKind) {}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) IBOutletAttr; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == IBOutletKind;
|
||||
}
|
||||
static bool classof(const IBOutletAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(NoReturn);
|
||||
DEF_SIMPLE_ATTR(AnalyzerNoReturn);
|
||||
DEF_SIMPLE_ATTR(Deprecated);
|
||||
|
||||
class SectionAttr : public Attr {
|
||||
std::string Name;
|
||||
public:
|
||||
SectionAttr(const std::string &N) : Attr(Section), Name(N) {}
|
||||
|
||||
const std::string& getName() const { return Name; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) SectionAttr(Name); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Section;
|
||||
}
|
||||
static bool classof(const SectionAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(Unavailable);
|
||||
DEF_SIMPLE_ATTR(Unused);
|
||||
DEF_SIMPLE_ATTR(Used);
|
||||
DEF_SIMPLE_ATTR(Weak);
|
||||
DEF_SIMPLE_ATTR(WeakImport);
|
||||
DEF_SIMPLE_ATTR(NoThrow);
|
||||
DEF_SIMPLE_ATTR(Const);
|
||||
DEF_SIMPLE_ATTR(Pure);
|
||||
|
||||
class NonNullAttr : public Attr {
|
||||
unsigned* ArgNums;
|
||||
unsigned Size;
|
||||
public:
|
||||
NonNullAttr(unsigned* arg_nums = 0, unsigned size = 0) : Attr(NonNull),
|
||||
ArgNums(0), Size(0) {
|
||||
|
||||
if (size == 0) return;
|
||||
assert(arg_nums);
|
||||
ArgNums = new unsigned[size];
|
||||
Size = size;
|
||||
memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
|
||||
}
|
||||
|
||||
virtual ~NonNullAttr() {
|
||||
delete [] ArgNums;
|
||||
}
|
||||
|
||||
typedef const unsigned *iterator;
|
||||
iterator begin() const { return ArgNums; }
|
||||
iterator end() const { return ArgNums + Size; }
|
||||
unsigned size() const { return Size; }
|
||||
|
||||
bool isNonNull(unsigned arg) const {
|
||||
return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
|
||||
}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) NonNullAttr(ArgNums, Size); }
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == NonNull; }
|
||||
static bool classof(const NonNullAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class FormatAttr : public Attr {
|
||||
std::string Type;
|
||||
int formatIdx, firstArg;
|
||||
public:
|
||||
FormatAttr(const std::string &type, int idx, int first) : Attr(Format),
|
||||
Type(type), formatIdx(idx), firstArg(first) {}
|
||||
|
||||
const std::string& getType() const { return Type; }
|
||||
void setType(const std::string &type) { Type = type; }
|
||||
int getFormatIdx() const { return formatIdx; }
|
||||
int getFirstArg() const { return firstArg; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) FormatAttr(Type, formatIdx, firstArg);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Format; }
|
||||
static bool classof(const FormatAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class FormatArgAttr : public Attr {
|
||||
int formatIdx;
|
||||
public:
|
||||
FormatArgAttr(int idx) : Attr(FormatArg), formatIdx(idx) {}
|
||||
int getFormatIdx() const { return formatIdx; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) FormatArgAttr(formatIdx);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == FormatArg; }
|
||||
static bool classof(const FormatArgAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class SentinelAttr : public Attr {
|
||||
int sentinel, NullPos;
|
||||
public:
|
||||
SentinelAttr(int sentinel_val, int nullPos) : Attr(Sentinel),
|
||||
sentinel(sentinel_val), NullPos(nullPos) {}
|
||||
int getSentinel() const { return sentinel; }
|
||||
int getNullPos() const { return NullPos; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) SentinelAttr(sentinel, NullPos);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Sentinel; }
|
||||
static bool classof(const SentinelAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class VisibilityAttr : public Attr {
|
||||
public:
|
||||
/// @brief An enumeration for the kinds of visibility of symbols.
|
||||
enum VisibilityTypes {
|
||||
DefaultVisibility = 0,
|
||||
HiddenVisibility,
|
||||
ProtectedVisibility
|
||||
};
|
||||
private:
|
||||
VisibilityTypes VisibilityType;
|
||||
public:
|
||||
VisibilityAttr(VisibilityTypes v) : Attr(Visibility),
|
||||
VisibilityType(v) {}
|
||||
|
||||
VisibilityTypes getVisibility() const { return VisibilityType; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) VisibilityAttr(VisibilityType); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Visibility; }
|
||||
static bool classof(const VisibilityAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(DLLImport);
|
||||
DEF_SIMPLE_ATTR(DLLExport);
|
||||
DEF_SIMPLE_ATTR(FastCall);
|
||||
DEF_SIMPLE_ATTR(StdCall);
|
||||
DEF_SIMPLE_ATTR(TransparentUnion);
|
||||
DEF_SIMPLE_ATTR(ObjCNSObject);
|
||||
DEF_SIMPLE_ATTR(ObjCException);
|
||||
|
||||
class OverloadableAttr : public Attr {
|
||||
public:
|
||||
OverloadableAttr() : Attr(Overloadable) { }
|
||||
|
||||
virtual bool isMerged() const { return false; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) OverloadableAttr;
|
||||
}
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
|
||||
static bool classof(const OverloadableAttr *) { return true; }
|
||||
};
|
||||
|
||||
class BlocksAttr : public Attr {
|
||||
public:
|
||||
enum BlocksAttrTypes {
|
||||
ByRef = 0
|
||||
};
|
||||
private:
|
||||
BlocksAttrTypes BlocksAttrType;
|
||||
public:
|
||||
BlocksAttr(BlocksAttrTypes t) : Attr(Blocks), BlocksAttrType(t) {}
|
||||
|
||||
BlocksAttrTypes getType() const { return BlocksAttrType; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) BlocksAttr(BlocksAttrType); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Blocks; }
|
||||
static bool classof(const BlocksAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class FunctionDecl;
|
||||
|
||||
class CleanupAttr : public Attr {
|
||||
FunctionDecl *FD;
|
||||
|
||||
public:
|
||||
CleanupAttr(FunctionDecl *fd) : Attr(Cleanup), FD(fd) {}
|
||||
|
||||
const FunctionDecl *getFunctionDecl() const { return FD; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) CleanupAttr(FD); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Cleanup; }
|
||||
static bool classof(const CleanupAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(Nodebug);
|
||||
DEF_SIMPLE_ATTR(WarnUnusedResult);
|
||||
DEF_SIMPLE_ATTR(Noinline);
|
||||
|
||||
class RegparmAttr : public Attr {
|
||||
unsigned NumParams;
|
||||
|
||||
public:
|
||||
RegparmAttr(unsigned np) : Attr(Regparm), NumParams(np) {}
|
||||
|
||||
unsigned getNumParams() const { return NumParams; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) RegparmAttr(NumParams);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Regparm; }
|
||||
static bool classof(const RegparmAttr *A) { return true; }
|
||||
};
|
||||
|
||||
// Checker-specific attributes.
|
||||
DEF_SIMPLE_ATTR(CFReturnsRetained);
|
||||
DEF_SIMPLE_ATTR(NSReturnsRetained);
|
||||
|
||||
#undef DEF_SIMPLE_ATTR
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
389
include/clang/AST/Builtins.def
Normal file
389
include/clang/AST/Builtins.def
Normal file
@ -0,0 +1,389 @@
|
||||
//===--- Builtins.def - Builtin function info database ----------*- 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 standard builtin function database. Users of this file
|
||||
// must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
|
||||
// adding stuff on demand.
|
||||
//
|
||||
// FIXME: This should really be a .td file, but that requires modifying tblgen.
|
||||
// Perhaps tblgen should have plugins.
|
||||
|
||||
// The first value provided to the macro specifies the function name of the
|
||||
// builtin, and results in a clang::builtin::BIXX enum value for XX.
|
||||
|
||||
// The second value provided to the macro specifies the type of the function
|
||||
// (result value, then each argument) as follows:
|
||||
// v -> void
|
||||
// b -> boolean
|
||||
// c -> char
|
||||
// s -> short
|
||||
// i -> int
|
||||
// f -> float
|
||||
// d -> double
|
||||
// z -> size_t
|
||||
// F -> constant CFString
|
||||
// a -> __builtin_va_list
|
||||
// A -> "reference" to __builtin_va_list
|
||||
// V -> Vector, following num elements and a base type.
|
||||
// P -> FILE
|
||||
// . -> "...". This may only occur at the end of the function list.
|
||||
//
|
||||
// Types maybe 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
|
||||
//
|
||||
// Types may be postfixed with the following modifiers:
|
||||
// * -> pointer
|
||||
// & -> reference
|
||||
// C -> const
|
||||
|
||||
// The third value provided to the macro specifies information about attributes
|
||||
// of the function. These must be kept in sync with the predicates in the
|
||||
// Builtin::Context class. Currently we have:
|
||||
// n -> nothrow
|
||||
// c -> const
|
||||
// F -> this is a libc/libm function with a '__builtin_' prefix added.
|
||||
// f -> this is a libc/libm function without the '__builtin_' prefix. It can
|
||||
// be followed by ':headername:' to state which header this function
|
||||
// comes from.
|
||||
// p:N: -> this is a printf-like function whose Nth argument is the format
|
||||
// string.
|
||||
// P:N: -> similar to the p:N: attribute, but the function is like vprintf
|
||||
// in that it accepts its arguments as a va_list rather than
|
||||
// through an ellipsis
|
||||
// e -> const, but only when -fmath-errno=0
|
||||
// FIXME: gcc has nonnull
|
||||
|
||||
#if defined(BUILTIN) && !defined(LIBBUILTIN)
|
||||
# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
|
||||
// Standard libc/libm functions:
|
||||
BUILTIN(__builtin_huge_val, "d", "nc")
|
||||
BUILTIN(__builtin_huge_valf, "f", "nc")
|
||||
BUILTIN(__builtin_huge_vall, "Ld", "nc")
|
||||
BUILTIN(__builtin_inf , "d" , "nc")
|
||||
BUILTIN(__builtin_inff , "f" , "nc")
|
||||
BUILTIN(__builtin_infl , "Ld" , "nc")
|
||||
BUILTIN(__builtin_nan, "dcC*" , "ncF")
|
||||
BUILTIN(__builtin_nanf, "fcC*" , "ncF")
|
||||
BUILTIN(__builtin_nanl, "LdcC*", "ncF")
|
||||
BUILTIN(__builtin_nans, "dcC*" , "ncF")
|
||||
BUILTIN(__builtin_nansf, "fcC*" , "ncF")
|
||||
BUILTIN(__builtin_nansl, "LdcC*", "ncF")
|
||||
BUILTIN(__builtin_abs , "ii" , "ncF")
|
||||
BUILTIN(__builtin_fabs , "dd" , "ncF")
|
||||
BUILTIN(__builtin_fabsf, "ff" , "ncF")
|
||||
BUILTIN(__builtin_fabsl, "LdLd", "ncF")
|
||||
BUILTIN(__builtin_copysign, "ddd", "ncF")
|
||||
BUILTIN(__builtin_copysignf, "fff", "ncF")
|
||||
BUILTIN(__builtin_copysignl, "LdLdLd", "ncF")
|
||||
BUILTIN(__builtin_powi , "ddi" , "nc")
|
||||
BUILTIN(__builtin_powif, "ffi" , "nc")
|
||||
BUILTIN(__builtin_powil, "LdLdi", "nc")
|
||||
|
||||
// FP Comparisons.
|
||||
BUILTIN(__builtin_isgreater , "i.", "nc")
|
||||
BUILTIN(__builtin_isgreaterequal, "i.", "nc")
|
||||
BUILTIN(__builtin_isless , "i.", "nc")
|
||||
BUILTIN(__builtin_islessequal , "i.", "nc")
|
||||
BUILTIN(__builtin_islessgreater , "i.", "nc")
|
||||
BUILTIN(__builtin_isunordered , "i.", "nc")
|
||||
|
||||
// Builtins for arithmetic.
|
||||
BUILTIN(__builtin_clz , "iUi" , "nc")
|
||||
BUILTIN(__builtin_clzl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_clzll, "iULLi", "nc")
|
||||
// TODO: int clzimax(uintmax_t)
|
||||
BUILTIN(__builtin_ctz , "iUi" , "nc")
|
||||
BUILTIN(__builtin_ctzl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_ctzll, "iULLi", "nc")
|
||||
// TODO: int ctzimax(uintmax_t)
|
||||
BUILTIN(__builtin_ffs , "iUi" , "nc")
|
||||
BUILTIN(__builtin_ffsl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_ffsll, "iULLi", "nc")
|
||||
BUILTIN(__builtin_parity , "iUi" , "nc")
|
||||
BUILTIN(__builtin_parityl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_parityll, "iULLi", "nc")
|
||||
BUILTIN(__builtin_popcount , "iUi" , "nc")
|
||||
BUILTIN(__builtin_popcountl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_popcountll, "iULLi", "nc")
|
||||
|
||||
// FIXME: These type signatures are not correct for targets with int != 32-bits
|
||||
// or with ULL != 64-bits.
|
||||
BUILTIN(__builtin_bswap32, "UiUi", "nc")
|
||||
BUILTIN(__builtin_bswap64, "ULLiULLi", "nc")
|
||||
|
||||
// Random GCC builtins
|
||||
BUILTIN(__builtin_constant_p, "Us.", "nc")
|
||||
BUILTIN(__builtin_classify_type, "i.", "nc")
|
||||
BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc")
|
||||
BUILTIN(__builtin_va_start, "vA.", "n")
|
||||
BUILTIN(__builtin_va_end, "vA", "n")
|
||||
BUILTIN(__builtin_va_copy, "vAA", "n")
|
||||
BUILTIN(__builtin_stdarg_start, "vA.", "n")
|
||||
BUILTIN(__builtin_bcmp, "iv*v*z", "n")
|
||||
BUILTIN(__builtin_bcopy, "vv*v*z", "n")
|
||||
BUILTIN(__builtin_bzero, "vv*z", "n")
|
||||
BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF")
|
||||
BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF")
|
||||
BUILTIN(__builtin_memmove, "v*v*vC*z", "nF")
|
||||
BUILTIN(__builtin_mempcpy, "v*v*vC*z", "nF")
|
||||
BUILTIN(__builtin_memset, "v*v*iz", "nF")
|
||||
BUILTIN(__builtin_stpcpy, "c*c*cC*", "nF")
|
||||
BUILTIN(__builtin_stpncpy, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin_strcasecmp, "icC*cC*", "nF")
|
||||
BUILTIN(__builtin_strcat, "c*c*cC*", "nF")
|
||||
BUILTIN(__builtin_strchr, "c*cC*i", "nF")
|
||||
BUILTIN(__builtin_strcmp, "icC*cC*", "nF")
|
||||
BUILTIN(__builtin_strcpy, "c*c*cC*", "nF")
|
||||
BUILTIN(__builtin_strcspn, "zcC*cC*", "nF")
|
||||
BUILTIN(__builtin_strdup, "c*cC*", "nF")
|
||||
BUILTIN(__builtin_strlen, "zcC*", "nF")
|
||||
BUILTIN(__builtin_strncasecmp, "icC*cC*z", "nF")
|
||||
BUILTIN(__builtin_strncat, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin_strncmp, "icC*cC*z", "nF")
|
||||
BUILTIN(__builtin_strncpy, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin_strndup, "c*cC*z", "nF")
|
||||
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_extract_return_addr, "v*v*", "n")
|
||||
BUILTIN(__builtin_frame_address, "v*Ui", "n")
|
||||
BUILTIN(__builtin_flt_rounds, "i", "nc")
|
||||
BUILTIN(__builtin_setjmp, "iv**", "")
|
||||
BUILTIN(__builtin_longjmp, "vv**i", "")
|
||||
BUILTIN(__builtin_unwind_init, "v", "")
|
||||
|
||||
// GCC Object size checking builtins
|
||||
BUILTIN(__builtin_object_size, "zv*i", "n")
|
||||
BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF")
|
||||
BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF")
|
||||
BUILTIN(__builtin___mempcpy_chk, "v*v*vC*zz", "nF")
|
||||
BUILTIN(__builtin___memset_chk, "v*v*izz", "nF")
|
||||
BUILTIN(__builtin___stpcpy_chk, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF")
|
||||
BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF")
|
||||
BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "Fp:4:")
|
||||
BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "Fp:3:")
|
||||
BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "FP:4:")
|
||||
BUILTIN(__builtin___vsprintf_chk, "ic*izcC*a", "FP:3:")
|
||||
BUILTIN(__builtin___fprintf_chk, "iP*icC*.", "Fp:2:")
|
||||
BUILTIN(__builtin___printf_chk, "iicC*.", "Fp:1:")
|
||||
BUILTIN(__builtin___vfprintf_chk, "iP*icC*a", "FP:2:")
|
||||
BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:")
|
||||
|
||||
BUILTIN(__builtin_expect, "iii" , "nc")
|
||||
BUILTIN(__builtin_prefetch, "vvC*.", "nc")
|
||||
BUILTIN(__builtin_trap, "v", "n")
|
||||
|
||||
BUILTIN(__builtin_shufflevector, "v." , "nc")
|
||||
|
||||
BUILTIN(__builtin_alloca, "v*z" , "n")
|
||||
|
||||
// "Overloaded" Atomic operator builtins. These are overloaded to support data
|
||||
// types of i8, i16, i32, i64, and i128. The front-end sees calls to the
|
||||
// non-suffixed version of these (which has a bogus type) and transforms them to
|
||||
// the right overloaded version in Sema (plus casts).
|
||||
|
||||
// FIXME: These assume that char -> i8, short -> i16, int -> i32,
|
||||
// long long -> i64.
|
||||
|
||||
BUILTIN(__sync_fetch_and_add, "v.", "")
|
||||
BUILTIN(__sync_fetch_and_add_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_fetch_and_add_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_fetch_and_add_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_fetch_and_add_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_fetch_and_add_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_fetch_and_sub, "v.", "")
|
||||
BUILTIN(__sync_fetch_and_sub_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_fetch_and_sub_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_fetch_and_sub_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_fetch_and_sub_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_fetch_and_sub_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_fetch_and_or, "v.", "")
|
||||
BUILTIN(__sync_fetch_and_or_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_fetch_and_or_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_fetch_and_or_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_fetch_and_or_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_fetch_and_or_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_fetch_and_and, "v.", "")
|
||||
BUILTIN(__sync_fetch_and_and_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_fetch_and_and_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_fetch_and_and_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_fetch_and_and_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_fetch_and_and_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_fetch_and_xor, "v.", "")
|
||||
BUILTIN(__sync_fetch_and_xor_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_fetch_and_xor_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_fetch_and_xor_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_fetch_and_xor_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_fetch_and_nand, "v.", "")
|
||||
BUILTIN(__sync_fetch_and_nand_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_fetch_and_nand_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_fetch_and_nand_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_fetch_and_nand_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
|
||||
BUILTIN(__sync_add_and_fetch, "v.", "")
|
||||
BUILTIN(__sync_add_and_fetch_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_add_and_fetch_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_add_and_fetch_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_add_and_fetch_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_add_and_fetch_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_sub_and_fetch, "v.", "")
|
||||
BUILTIN(__sync_sub_and_fetch_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_sub_and_fetch_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_sub_and_fetch_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_sub_and_fetch_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_sub_and_fetch_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_or_and_fetch, "v.", "")
|
||||
BUILTIN(__sync_or_and_fetch_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_or_and_fetch_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_or_and_fetch_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_or_and_fetch_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_or_and_fetch_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_and_and_fetch, "v.", "")
|
||||
BUILTIN(__sync_and_and_fetch_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_and_and_fetch_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_and_and_fetch_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_and_and_fetch_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_and_and_fetch_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_xor_and_fetch, "v.", "")
|
||||
BUILTIN(__sync_xor_and_fetch_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_xor_and_fetch_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_xor_and_fetch_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_xor_and_fetch_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_nand_and_fetch, "v.", "")
|
||||
BUILTIN(__sync_nand_and_fetch_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_nand_and_fetch_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_nand_and_fetch_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_nand_and_fetch_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
|
||||
BUILTIN(__sync_bool_compare_and_swap, "v.", "")
|
||||
BUILTIN(__sync_bool_compare_and_swap_1, "bc*cc.", "n")
|
||||
BUILTIN(__sync_bool_compare_and_swap_2, "bs*ss.", "n")
|
||||
BUILTIN(__sync_bool_compare_and_swap_4, "bi*ii.", "n")
|
||||
BUILTIN(__sync_bool_compare_and_swap_8, "bLLi*LLi.", "n")
|
||||
BUILTIN(__sync_bool_compare_and_swap_16, "bLLLi*LLLiLLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_val_compare_and_swap, "v.", "")
|
||||
BUILTIN(__sync_val_compare_and_swap_1, "cc*cc.", "n")
|
||||
BUILTIN(__sync_val_compare_and_swap_2, "ss*ss.", "n")
|
||||
BUILTIN(__sync_val_compare_and_swap_4, "ii*ii.", "n")
|
||||
BUILTIN(__sync_val_compare_and_swap_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLi*LLLiLLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_lock_test_and_set, "v.", "")
|
||||
BUILTIN(__sync_lock_test_and_set_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_lock_test_and_set_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_lock_test_and_set_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_lock_test_and_set_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_lock_test_and_set_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_lock_release, "v.", "")
|
||||
BUILTIN(__sync_lock_release_1, "vc*.", "n")
|
||||
BUILTIN(__sync_lock_release_2, "vs*.", "n")
|
||||
BUILTIN(__sync_lock_release_4, "vi*.", "n")
|
||||
BUILTIN(__sync_lock_release_8, "vLLi*.", "n")
|
||||
BUILTIN(__sync_lock_release_16, "vLLLi*.", "n")
|
||||
|
||||
|
||||
|
||||
// Non-overloaded atomic builtins.
|
||||
BUILTIN(__sync_synchronize, "v.", "n")
|
||||
// LLVM instruction builtin [Clang extension].
|
||||
BUILTIN(__builtin_llvm_memory_barrier,"vbbbbb", "n")
|
||||
// GCC does not support these, they are a Clang extension.
|
||||
BUILTIN(__sync_fetch_and_min, "ii*i", "n")
|
||||
BUILTIN(__sync_fetch_and_max, "ii*i", "n")
|
||||
BUILTIN(__sync_fetch_and_umin, "UiUi*Ui", "n")
|
||||
BUILTIN(__sync_fetch_and_umax, "UiUi*Ui", "n")
|
||||
|
||||
// Builtin library functions
|
||||
LIBBUILTIN(alloca, "v*z", "f", "stdlib.h")
|
||||
LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h")
|
||||
LIBBUILTIN(malloc, "v*z", "f", "stdlib.h")
|
||||
LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h")
|
||||
LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h")
|
||||
LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h")
|
||||
LIBBUILTIN(memset, "v*v*iz", "f", "string.h")
|
||||
LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strchr, "c*cC*i", "f", "string.h")
|
||||
LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h")
|
||||
LIBBUILTIN(strlen, "zcC*", "f", "string.h")
|
||||
LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h")
|
||||
LIBBUILTIN(strncpy, "c*c*cC*z", "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(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, "iP*cC*a", "fP:1:", "stdio.h")
|
||||
LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h")
|
||||
LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h")
|
||||
|
||||
// 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")
|
||||
|
||||
// FIXME: asprintf and vasprintf aren't C99 functions. Should they be
|
||||
// target-specific builtins, perhaps?
|
||||
|
||||
// Builtin math library functions
|
||||
LIBBUILTIN(pow, "ddd", "fe", "math.h")
|
||||
LIBBUILTIN(powl, "LdLdLd", "fe", "math.h")
|
||||
LIBBUILTIN(powf, "fff", "fe", "math.h")
|
||||
|
||||
LIBBUILTIN(sqrt, "dd", "fe", "math.h")
|
||||
LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h")
|
||||
LIBBUILTIN(sqrtf, "ff", "fe", "math.h")
|
||||
|
||||
LIBBUILTIN(sin, "dd", "fe", "math.h")
|
||||
LIBBUILTIN(sinl, "LdLd", "fe", "math.h")
|
||||
LIBBUILTIN(sinf, "ff", "fe", "math.h")
|
||||
|
||||
LIBBUILTIN(cos, "dd", "fe", "math.h")
|
||||
LIBBUILTIN(cosl, "LdLd", "fe", "math.h")
|
||||
LIBBUILTIN(cosf, "ff", "fe", "math.h")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef LIBBUILTIN
|
137
include/clang/AST/Builtins.h
Normal file
137
include/clang/AST/Builtins.h
Normal file
@ -0,0 +1,137 @@
|
||||
//===--- Builtins.h - Builtin function header -------------------*- 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 enum values for all the target-independent builtin
|
||||
// functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_BUILTINS_H
|
||||
#define LLVM_CLANG_AST_BUILTINS_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
class TargetInfo;
|
||||
class IdentifierTable;
|
||||
class ASTContext;
|
||||
class QualType;
|
||||
|
||||
namespace Builtin {
|
||||
enum ID {
|
||||
NotBuiltin = 0, // This is not a builtin function.
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "clang/AST/Builtins.def"
|
||||
FirstTSBuiltin
|
||||
};
|
||||
|
||||
struct Info {
|
||||
const char *Name, *Type, *Attributes, *HeaderName;
|
||||
bool Suppressed;
|
||||
|
||||
bool operator==(const Info &RHS) const {
|
||||
return !strcmp(Name, RHS.Name) &&
|
||||
!strcmp(Type, RHS.Type) &&
|
||||
!strcmp(Attributes, RHS.Attributes);
|
||||
}
|
||||
bool operator!=(const Info &RHS) const { return !(*this == RHS); }
|
||||
};
|
||||
|
||||
/// Builtin::Context - This holds information about target-independent and
|
||||
/// target-specific builtins, allowing easy queries by clients.
|
||||
class Context {
|
||||
const Info *TSRecords;
|
||||
unsigned NumTSRecords;
|
||||
public:
|
||||
Context() : TSRecords(0), NumTSRecords(0) {}
|
||||
|
||||
/// \brief Load all of the target builtins. This should be called
|
||||
/// prior to initializing the builtin identifiers.
|
||||
void InitializeTargetBuiltins(const TargetInfo &Target);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// \brief Popular the vector with the names of all of the builtins.
|
||||
void GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
|
||||
bool NoBuiltins);
|
||||
|
||||
/// Builtin::GetName - Return the identifier name for the specified builtin,
|
||||
/// e.g. "__builtin_abs".
|
||||
const char *GetName(unsigned ID) const {
|
||||
return GetRecord(ID).Name;
|
||||
}
|
||||
|
||||
/// isConst - Return true if this function has no side effects and doesn't
|
||||
/// read memory.
|
||||
bool isConst(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'c') != 0;
|
||||
}
|
||||
|
||||
/// isNoThrow - Return true if we know this builtin never throws an exception.
|
||||
bool isNoThrow(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'n') != 0;
|
||||
}
|
||||
|
||||
/// isLibFunction - Return true if this is a builtin for a libc/libm function,
|
||||
/// with a "__builtin_" prefix (e.g. __builtin_abs).
|
||||
bool isLibFunction(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'F') != 0;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this builtin is a predefined libc/libm
|
||||
/// function, such as "malloc", where we know the signature a
|
||||
/// priori.
|
||||
bool isPredefinedLibFunction(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'f') != 0;
|
||||
}
|
||||
|
||||
/// \brief If this is a library function that comes from a specific
|
||||
/// header, retrieve that header name.
|
||||
const char *getHeaderName(unsigned ID) const {
|
||||
return GetRecord(ID).HeaderName;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this builtin is like printf in its
|
||||
/// formatting rules and, if so, set the index to the format string
|
||||
/// argument and whether this function as a va_list argument.
|
||||
bool isPrintfLike(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
|
||||
/// disabled.
|
||||
bool isConstWithoutErrno(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'e') != 0;
|
||||
}
|
||||
|
||||
/// GetBuiltinType - Return the type for the specified builtin.
|
||||
enum GetBuiltinTypeError {
|
||||
GE_None, //< No error
|
||||
GE_Missing_FILE //< Missing the FILE type from <stdio.h>
|
||||
};
|
||||
QualType GetBuiltinType(unsigned ID, ASTContext &Context,
|
||||
GetBuiltinTypeError &Error) const;
|
||||
private:
|
||||
const Info &GetRecord(unsigned ID) const;
|
||||
};
|
||||
|
||||
}
|
||||
} // end namespace clang
|
||||
#endif
|
405
include/clang/AST/CFG.h
Normal file
405
include/clang/AST/CFG.h
Normal file
@ -0,0 +1,405 @@
|
||||
//===--- CFG.h - Classes for representing and building CFGs------*- 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 CFG and CFGBuilder classes for representing and
|
||||
// building Control-Flow Graphs (CFGs) from ASTs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_CFG_H
|
||||
#define LLVM_CLANG_CFG_H
|
||||
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
class Stmt;
|
||||
class Expr;
|
||||
class CFG;
|
||||
class PrinterHelper;
|
||||
class BlockEdge;
|
||||
|
||||
/// CFGBlock - Represents a single basic block in a source-level CFG.
|
||||
/// It consists of:
|
||||
///
|
||||
/// (1) A set of statements/expressions (which may contain subexpressions).
|
||||
/// (2) A "terminator" statement (not in the set of statements).
|
||||
/// (3) A list of successors and predecessors.
|
||||
///
|
||||
/// Terminator: The terminator represents the type of control-flow that occurs
|
||||
/// at the end of the basic block. The terminator is a Stmt* referring to an
|
||||
/// AST node that has control-flow: if-statements, breaks, loops, etc.
|
||||
/// If the control-flow is conditional, the condition expression will appear
|
||||
/// within the set of statements in the block (usually the last statement).
|
||||
///
|
||||
/// Predecessors: the order in the set of predecessors is arbitrary.
|
||||
///
|
||||
/// Successors: the order in the set of successors is NOT arbitrary. We
|
||||
/// currently have the following orderings based on the terminator:
|
||||
///
|
||||
/// Terminator Successor Ordering
|
||||
/// -----------------------------------------------------
|
||||
/// if Then Block; Else Block
|
||||
/// ? operator LHS expression; RHS expression
|
||||
/// &&, || expression that uses result of && or ||, RHS
|
||||
///
|
||||
class CFGBlock {
|
||||
typedef std::vector<Stmt*> StatementListTy;
|
||||
/// Stmts - The set of statements in the basic block.
|
||||
StatementListTy Stmts;
|
||||
|
||||
/// Label - An (optional) label that prefixes the executable
|
||||
/// statements in the block. When this variable is non-NULL, it is
|
||||
/// either an instance of LabelStmt or SwitchCase.
|
||||
Stmt *Label;
|
||||
|
||||
/// Terminator - The terminator for a basic block that
|
||||
/// indicates the type of control-flow that occurs between a block
|
||||
/// and its successors.
|
||||
Stmt *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
|
||||
/// refer to the loop statement for such blocks (and be null otherwise).
|
||||
const Stmt *LoopTarget;
|
||||
|
||||
/// BlockID - A numerical ID assigned to a CFGBlock during construction
|
||||
/// of the CFG.
|
||||
unsigned BlockID;
|
||||
|
||||
/// Predecessors/Successors - Keep track of the predecessor / successor
|
||||
/// CFG blocks.
|
||||
typedef std::vector<CFGBlock*> AdjacentBlocks;
|
||||
AdjacentBlocks Preds;
|
||||
AdjacentBlocks Succs;
|
||||
|
||||
public:
|
||||
explicit CFGBlock(unsigned blockid) : Label(NULL), Terminator(NULL),
|
||||
LoopTarget(NULL), BlockID(blockid) {}
|
||||
~CFGBlock() {};
|
||||
|
||||
// Statement iterators
|
||||
typedef StatementListTy::iterator iterator;
|
||||
typedef StatementListTy::const_iterator const_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
|
||||
Stmt* front() const { return Stmts.front(); }
|
||||
Stmt* back() const { return Stmts.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(); }
|
||||
|
||||
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(); }
|
||||
|
||||
unsigned size() const { return Stmts.size(); }
|
||||
bool empty() const { return Stmts.empty(); }
|
||||
|
||||
Stmt* operator[](size_t i) const { assert (i < size()); return Stmts[i]; }
|
||||
|
||||
// CFG iterators
|
||||
typedef AdjacentBlocks::iterator pred_iterator;
|
||||
typedef AdjacentBlocks::const_iterator const_pred_iterator;
|
||||
typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator;
|
||||
typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator;
|
||||
|
||||
typedef AdjacentBlocks::iterator succ_iterator;
|
||||
typedef AdjacentBlocks::const_iterator const_succ_iterator;
|
||||
typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator;
|
||||
typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator;
|
||||
|
||||
pred_iterator pred_begin() { return Preds.begin(); }
|
||||
pred_iterator pred_end() { return Preds.end(); }
|
||||
const_pred_iterator pred_begin() const { return Preds.begin(); }
|
||||
const_pred_iterator pred_end() const { return Preds.end(); }
|
||||
|
||||
pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); }
|
||||
pred_reverse_iterator pred_rend() { return Preds.rend(); }
|
||||
const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); }
|
||||
const_pred_reverse_iterator pred_rend() const { return Preds.rend(); }
|
||||
|
||||
succ_iterator succ_begin() { return Succs.begin(); }
|
||||
succ_iterator succ_end() { return Succs.end(); }
|
||||
const_succ_iterator succ_begin() const { return Succs.begin(); }
|
||||
const_succ_iterator succ_end() const { return Succs.end(); }
|
||||
|
||||
succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); }
|
||||
succ_reverse_iterator succ_rend() { return Succs.rend(); }
|
||||
const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); }
|
||||
const_succ_reverse_iterator succ_rend() const { return Succs.rend(); }
|
||||
|
||||
unsigned succ_size() const { return Succs.size(); }
|
||||
bool succ_empty() const { return Succs.empty(); }
|
||||
|
||||
unsigned pred_size() const { return Preds.size(); }
|
||||
bool pred_empty() const { return Preds.empty(); }
|
||||
|
||||
// Manipulation of block contents
|
||||
|
||||
void appendStmt(Stmt* Statement) { Stmts.push_back(Statement); }
|
||||
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; }
|
||||
|
||||
Stmt* getTerminatorCondition();
|
||||
|
||||
const Stmt* getTerminatorCondition() const {
|
||||
return const_cast<CFGBlock*>(this)->getTerminatorCondition();
|
||||
}
|
||||
|
||||
const Stmt *getLoopTarget() const { return LoopTarget; }
|
||||
|
||||
bool hasBinaryBranchTerminator() const;
|
||||
|
||||
Stmt* getLabel() { return Label; }
|
||||
const Stmt* getLabel() const { return Label; }
|
||||
|
||||
void reverseStmts();
|
||||
|
||||
void addSuccessor(CFGBlock* Block) {
|
||||
Block->Preds.push_back(this);
|
||||
Succs.push_back(Block);
|
||||
}
|
||||
|
||||
unsigned getBlockID() const { return BlockID; }
|
||||
|
||||
void dump(const CFG* cfg) const;
|
||||
void print(llvm::raw_ostream& OS, const CFG* cfg) const;
|
||||
void printTerminator(llvm::raw_ostream& OS) const;
|
||||
};
|
||||
|
||||
|
||||
/// 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
|
||||
/// represents the Exit point of the CFG. A CFG will also contain a designated
|
||||
/// Entry block. The CFG solely represents control-flow; it consists of
|
||||
/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG
|
||||
/// was constructed from.
|
||||
class CFG {
|
||||
public:
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Construction & Manipulation.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// buildCFG - Builds a CFG from an AST. The responsibility to free the
|
||||
/// constructed CFG belongs to the caller.
|
||||
static CFG* buildCFG(Stmt* AST);
|
||||
|
||||
/// createBlock - Create a new block in the CFG. The CFG owns the block;
|
||||
/// the caller should not directly free it.
|
||||
CFGBlock* createBlock();
|
||||
|
||||
/// setEntry - Set the entry block of the CFG. This is typically used
|
||||
/// only during CFG construction. Most CFG clients expect that the
|
||||
/// entry block has no predecessors and contains no statements.
|
||||
void setEntry(CFGBlock *B) { Entry = B; }
|
||||
|
||||
/// setExit - Set the exit block of the CFG. This is typically used
|
||||
/// only during CFG construction. Most CFG clients expect that the
|
||||
/// exit block has no successors and contains no statements.
|
||||
void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Block Iterators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
typedef std::list<CFGBlock> CFGBlockListTy;
|
||||
|
||||
typedef CFGBlockListTy::iterator iterator;
|
||||
typedef CFGBlockListTy::const_iterator const_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
CFGBlock& front() { return Blocks.front(); }
|
||||
CFGBlock& back() { return Blocks.back(); }
|
||||
|
||||
iterator begin() { return Blocks.begin(); }
|
||||
iterator end() { return Blocks.end(); }
|
||||
const_iterator begin() const { return Blocks.begin(); }
|
||||
const_iterator end() const { return Blocks.end(); }
|
||||
|
||||
reverse_iterator rbegin() { return Blocks.rbegin(); }
|
||||
reverse_iterator rend() { return Blocks.rend(); }
|
||||
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
|
||||
const_reverse_iterator rend() const { return Blocks.rend(); }
|
||||
|
||||
CFGBlock& getEntry() { return *Entry; }
|
||||
const CFGBlock& getEntry() const { return *Entry; }
|
||||
CFGBlock& getExit() { return *Exit; }
|
||||
const CFGBlock& getExit() const { return *Exit; }
|
||||
|
||||
CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; }
|
||||
const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Member templates useful for various batch operations over CFGs.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
template <typename CALLBACK>
|
||||
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);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Introspection.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct BlkExprNumTy {
|
||||
const signed Idx;
|
||||
explicit BlkExprNumTy(signed idx) : Idx(idx) {}
|
||||
explicit BlkExprNumTy() : Idx(-1) {}
|
||||
operator bool() const { return Idx >= 0; }
|
||||
operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
|
||||
};
|
||||
|
||||
bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
|
||||
BlkExprNumTy getBlkExprNum(const Stmt* S);
|
||||
unsigned getNumBlkExprs();
|
||||
|
||||
unsigned getNumBlockIDs() const { return NumBlockIDs; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Debugging: Pretty-Printing and Visualization.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void viewCFG() const;
|
||||
void print(llvm::raw_ostream& OS) const;
|
||||
void dump() const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal: constructors and data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
|
||||
BlkExprMap(NULL) {};
|
||||
|
||||
~CFG();
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() {
|
||||
return Alloc;
|
||||
}
|
||||
|
||||
private:
|
||||
CFGBlock* Entry;
|
||||
CFGBlock* Exit;
|
||||
CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
|
||||
// for indirect gotos
|
||||
CFGBlockListTy Blocks;
|
||||
unsigned NumBlockIDs;
|
||||
|
||||
// BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
|
||||
// It represents a map from Expr* to integers to record the set of
|
||||
// block-level expressions and their "statement number" in the CFG.
|
||||
void* BlkExprMap;
|
||||
|
||||
/// Alloc - An internal allocator.
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GraphTraits specializations for CFG basic block graphs (source-level CFGs)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Traits for: CFGBlock
|
||||
|
||||
template <> struct GraphTraits<clang::CFGBlock* > {
|
||||
typedef clang::CFGBlock NodeType;
|
||||
typedef clang::CFGBlock::succ_iterator ChildIteratorType;
|
||||
|
||||
static NodeType* getEntryNode(clang::CFGBlock* BB)
|
||||
{ return BB; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->succ_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const clang::CFGBlock* > {
|
||||
typedef const clang::CFGBlock NodeType;
|
||||
typedef clang::CFGBlock::const_succ_iterator ChildIteratorType;
|
||||
|
||||
static NodeType* getEntryNode(const clang::CFGBlock* BB)
|
||||
{ return BB; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->succ_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > {
|
||||
typedef const clang::CFGBlock NodeType;
|
||||
typedef clang::CFGBlock::const_pred_iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(Inverse<const clang::CFGBlock*> G)
|
||||
{ return G.Graph; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->pred_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->pred_end(); }
|
||||
};
|
||||
|
||||
// Traits for: CFG
|
||||
|
||||
template <> struct GraphTraits<clang::CFG* >
|
||||
: public GraphTraits<clang::CFGBlock* > {
|
||||
|
||||
typedef clang::CFG::iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode(clang::CFG* F) { return &F->getEntry(); }
|
||||
static nodes_iterator nodes_begin(clang::CFG* F) { return F->begin(); }
|
||||
static nodes_iterator nodes_end(clang::CFG* F) { return F->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits< const clang::CFG* >
|
||||
: public GraphTraits< const clang::CFGBlock* > {
|
||||
|
||||
typedef clang::CFG::const_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode( const clang::CFG* F) { return &F->getEntry(); }
|
||||
static nodes_iterator nodes_begin( const clang::CFG* F) { return F->begin(); }
|
||||
static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const clang::CFG*> >
|
||||
: public GraphTraits<Inverse<const clang::CFGBlock*> > {
|
||||
|
||||
typedef clang::CFG::const_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode(const clang::CFG* F) { return &F->getExit(); }
|
||||
static nodes_iterator nodes_begin(const clang::CFG* F) { return F->begin();}
|
||||
static nodes_iterator nodes_end(const clang::CFG* F) { return F->end(); }
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
1409
include/clang/AST/Decl.h
Normal file
1409
include/clang/AST/Decl.h
Normal file
File diff suppressed because it is too large
Load Diff
900
include/clang/AST/DeclBase.h
Normal file
900
include/clang/AST/DeclBase.h
Normal file
@ -0,0 +1,900 @@
|
||||
//===-- DeclBase.h - Base Classes for representing declarations -*- 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 Decl and DeclContext interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLBASE_H
|
||||
#define LLVM_CLANG_AST_DECLBASE_H
|
||||
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Type.h"
|
||||
// FIXME: Layering violation
|
||||
#include "clang/Parse/AccessSpecifier.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
||||
namespace clang {
|
||||
class DeclContext;
|
||||
class TranslationUnitDecl;
|
||||
class NamespaceDecl;
|
||||
class UsingDirectiveDecl;
|
||||
class NamedDecl;
|
||||
class FunctionDecl;
|
||||
class CXXRecordDecl;
|
||||
class EnumDecl;
|
||||
class ObjCMethodDecl;
|
||||
class ObjCContainerDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCCategoryDecl;
|
||||
class ObjCProtocolDecl;
|
||||
class ObjCImplementationDecl;
|
||||
class ObjCCategoryImplDecl;
|
||||
class LinkageSpecDecl;
|
||||
class BlockDecl;
|
||||
class DeclarationName;
|
||||
class CompoundStmt;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
// DeclContext* is only 4-byte aligned on 32-bit systems.
|
||||
template<>
|
||||
class PointerLikeTypeTraits<clang::DeclContext*> {
|
||||
typedef clang::DeclContext* PT;
|
||||
public:
|
||||
static inline void *getAsVoidPointer(PT P) { return P; }
|
||||
static inline PT getFromVoidPointer(void *P) {
|
||||
return static_cast<PT>(P);
|
||||
}
|
||||
enum { NumLowBitsAvailable = 2 };
|
||||
};
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// Decl - This represents one declaration (or definition), e.g. a variable,
|
||||
/// typedef, function, struct, etc.
|
||||
///
|
||||
class Decl {
|
||||
public:
|
||||
/// \brief Lists the kind of concrete classes of Decl.
|
||||
enum Kind {
|
||||
#define DECL(Derived, Base) Derived,
|
||||
#define DECL_RANGE(CommonBase, Start, End) \
|
||||
CommonBase##First = Start, CommonBase##Last = End,
|
||||
#define LAST_DECL_RANGE(CommonBase, Start, End) \
|
||||
CommonBase##First = Start, CommonBase##Last = End
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
};
|
||||
|
||||
/// IdentifierNamespace - According to C99 6.2.3, there are four
|
||||
/// namespaces, labels, tags, members and ordinary
|
||||
/// identifiers. These are meant as bitmasks, so that searches in
|
||||
/// C++ can look into the "tag" namespace during ordinary lookup. We
|
||||
/// use additional namespaces for Objective-C entities.
|
||||
enum IdentifierNamespace {
|
||||
IDNS_Label = 0x1,
|
||||
IDNS_Tag = 0x2,
|
||||
IDNS_Member = 0x4,
|
||||
IDNS_Ordinary = 0x8,
|
||||
IDNS_ObjCProtocol = 0x10,
|
||||
IDNS_ObjCImplementation = 0x20,
|
||||
IDNS_ObjCCategoryImpl = 0x40
|
||||
};
|
||||
|
||||
/// ObjCDeclQualifier - Qualifier used on types in method declarations
|
||||
/// for remote messaging. They are meant for the arguments though and
|
||||
/// applied to the Decls (ObjCMethodDecl and ParmVarDecl).
|
||||
enum ObjCDeclQualifier {
|
||||
OBJC_TQ_None = 0x0,
|
||||
OBJC_TQ_In = 0x1,
|
||||
OBJC_TQ_Inout = 0x2,
|
||||
OBJC_TQ_Out = 0x4,
|
||||
OBJC_TQ_Bycopy = 0x8,
|
||||
OBJC_TQ_Byref = 0x10,
|
||||
OBJC_TQ_Oneway = 0x20
|
||||
};
|
||||
|
||||
private:
|
||||
/// NextDeclInContext - The next declaration within the same lexical
|
||||
/// DeclContext. These pointers form the linked list that is
|
||||
/// traversed via DeclContext's decls_begin()/decls_end().
|
||||
Decl *NextDeclInContext;
|
||||
|
||||
friend class DeclContext;
|
||||
|
||||
struct MultipleDC {
|
||||
DeclContext *SemanticDC;
|
||||
DeclContext *LexicalDC;
|
||||
};
|
||||
|
||||
|
||||
/// DeclCtx - Holds either a DeclContext* or a MultipleDC*.
|
||||
/// For declarations that don't contain C++ scope specifiers, it contains
|
||||
/// the DeclContext where the Decl was declared.
|
||||
/// For declarations with C++ scope specifiers, it contains a MultipleDC*
|
||||
/// with the context where it semantically belongs (SemanticDC) and the
|
||||
/// context where it was lexically declared (LexicalDC).
|
||||
/// e.g.:
|
||||
///
|
||||
/// namespace A {
|
||||
/// void f(); // SemanticDC == LexicalDC == 'namespace A'
|
||||
/// }
|
||||
/// void A::f(); // SemanticDC == namespace 'A'
|
||||
/// // LexicalDC == global namespace
|
||||
llvm::PointerUnion<DeclContext*, MultipleDC*> DeclCtx;
|
||||
|
||||
inline bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); }
|
||||
inline bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); }
|
||||
inline MultipleDC *getMultipleDC() const {
|
||||
return DeclCtx.get<MultipleDC*>();
|
||||
}
|
||||
inline DeclContext *getSemanticDC() const {
|
||||
return DeclCtx.get<DeclContext*>();
|
||||
}
|
||||
|
||||
/// Loc - The location that this decl.
|
||||
SourceLocation Loc;
|
||||
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Kind DeclKind : 8;
|
||||
|
||||
/// InvalidDecl - This indicates a semantic error occurred.
|
||||
unsigned int InvalidDecl : 1;
|
||||
|
||||
/// HasAttrs - This indicates whether the decl has attributes or not.
|
||||
unsigned int HasAttrs : 1;
|
||||
|
||||
/// Implicit - Whether this declaration was implicitly generated by
|
||||
/// the implementation rather than explicitly written by the user.
|
||||
bool Implicit : 1;
|
||||
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 8;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void CheckAccessDeclContext() const;
|
||||
#else
|
||||
void CheckAccessDeclContext() const { }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
|
||||
unsigned Access : 2;
|
||||
friend class CXXClassMemberWrapper;
|
||||
|
||||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: NextDeclInContext(0), DeclCtx(DC),
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)), Access(AS_none) {
|
||||
if (Decl::CollectingStats()) addDeclKind(DK);
|
||||
}
|
||||
|
||||
virtual ~Decl();
|
||||
|
||||
public:
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
Kind getKind() const { return DeclKind; }
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
Decl *getNextDeclInContext() { return NextDeclInContext; }
|
||||
const Decl *getNextDeclInContext() const { return NextDeclInContext; }
|
||||
|
||||
DeclContext *getDeclContext() {
|
||||
if (isInSemaDC())
|
||||
return getSemanticDC();
|
||||
return getMultipleDC()->SemanticDC;
|
||||
}
|
||||
const DeclContext *getDeclContext() const {
|
||||
return const_cast<Decl*>(this)->getDeclContext();
|
||||
}
|
||||
|
||||
void setAccess(AccessSpecifier AS) {
|
||||
Access = AS;
|
||||
CheckAccessDeclContext();
|
||||
}
|
||||
|
||||
AccessSpecifier getAccess() const {
|
||||
CheckAccessDeclContext();
|
||||
return AccessSpecifier(Access);
|
||||
}
|
||||
|
||||
bool hasAttrs() const { return HasAttrs; }
|
||||
void addAttr(Attr *attr);
|
||||
const Attr *getAttrs() const {
|
||||
if (!HasAttrs) return 0; // common case, no attributes.
|
||||
return getAttrsImpl(); // Uncommon case, out of line hash lookup.
|
||||
}
|
||||
void swapAttrs(Decl *D);
|
||||
void invalidateAttrs();
|
||||
|
||||
template<typename T> const T *getAttr() const {
|
||||
for (const Attr *attr = getAttrs(); attr; attr = attr->getNext())
|
||||
if (const T *V = dyn_cast<T>(attr))
|
||||
return V;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T> bool hasAttr() const {
|
||||
return getAttr<T>() != 0;
|
||||
}
|
||||
|
||||
/// setInvalidDecl - Indicates the Decl had a semantic error. This
|
||||
/// allows for graceful error recovery.
|
||||
void setInvalidDecl(bool Invalid = true) { InvalidDecl = Invalid; }
|
||||
bool isInvalidDecl() const { return (bool) InvalidDecl; }
|
||||
|
||||
/// isImplicit - Indicates whether the declaration was implicitly
|
||||
/// generated by the implementation. If false, this declaration
|
||||
/// was written explicitly in the source code.
|
||||
bool isImplicit() const { return Implicit; }
|
||||
void setImplicit(bool I = true) { Implicit = I; }
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
bool isInIdentifierNamespace(unsigned NS) const {
|
||||
return getIdentifierNamespace() & NS;
|
||||
}
|
||||
static unsigned getIdentifierNamespaceForKind(Kind DK);
|
||||
|
||||
|
||||
/// getLexicalDeclContext - The declaration context where this Decl was
|
||||
/// lexically declared (LexicalDC). May be different from
|
||||
/// getDeclContext() (SemanticDC).
|
||||
/// e.g.:
|
||||
///
|
||||
/// namespace A {
|
||||
/// void f(); // SemanticDC == LexicalDC == 'namespace A'
|
||||
/// }
|
||||
/// void A::f(); // SemanticDC == namespace 'A'
|
||||
/// // LexicalDC == global namespace
|
||||
DeclContext *getLexicalDeclContext() {
|
||||
if (isInSemaDC())
|
||||
return getSemanticDC();
|
||||
return getMultipleDC()->LexicalDC;
|
||||
}
|
||||
const DeclContext *getLexicalDeclContext() const {
|
||||
return const_cast<Decl*>(this)->getLexicalDeclContext();
|
||||
}
|
||||
|
||||
/// setDeclContext - Set both the semantic and lexical DeclContext
|
||||
/// to DC.
|
||||
void setDeclContext(DeclContext *DC);
|
||||
|
||||
void setLexicalDeclContext(DeclContext *DC);
|
||||
|
||||
// isDefinedOutsideFunctionOrMethod - This predicate returns true if this
|
||||
// scoped decl is defined outside the current function or method. This is
|
||||
// roughly global variables and functions, but also handles enums (which could
|
||||
// be defined inside or outside a function etc).
|
||||
bool isDefinedOutsideFunctionOrMethod() const;
|
||||
|
||||
/// getBody - If this Decl represents a declaration for a body of code,
|
||||
/// such as a function or method definition, this method returns the
|
||||
/// top-level Stmt* of that body. Otherwise this method returns null.
|
||||
virtual Stmt* getBody(ASTContext &Context) const { return 0; }
|
||||
|
||||
/// getCompoundBody - Returns getBody(), dyn_casted to a CompoundStmt.
|
||||
CompoundStmt* getCompoundBody(ASTContext &Context) const;
|
||||
|
||||
/// getBodyRBrace - Gets the right brace of the body, if a body exists.
|
||||
/// This works whether the body is a CompoundStmt or a CXXTryStmt.
|
||||
SourceLocation getBodyRBrace(ASTContext &Context) const;
|
||||
|
||||
// global temp stats (until we have a per-module visitor)
|
||||
static void addDeclKind(Kind k);
|
||||
static bool CollectingStats(bool Enable = false);
|
||||
static void PrintStats();
|
||||
|
||||
/// isTemplateParameter - Determines whether this declartion is a
|
||||
/// template parameter.
|
||||
bool isTemplateParameter() const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *) { return true; }
|
||||
static DeclContext *castToDeclContext(const Decl *);
|
||||
static Decl *castFromDeclContext(const DeclContext *);
|
||||
|
||||
/// Destroy - Call destructors and release memory.
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
void print(llvm::raw_ostream &Out, ASTContext &Context,
|
||||
unsigned Indentation = 0);
|
||||
void print(llvm::raw_ostream &Out, ASTContext &Context,
|
||||
const PrintingPolicy &Policy, unsigned Indentation = 0);
|
||||
static void printGroup(Decl** Begin, unsigned NumDecls,
|
||||
llvm::raw_ostream &Out, ASTContext &Context,
|
||||
const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0);
|
||||
void dump(ASTContext &Context);
|
||||
|
||||
private:
|
||||
const Attr *getAttrsImpl() const;
|
||||
|
||||
};
|
||||
|
||||
/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when
|
||||
/// doing something to a specific decl.
|
||||
class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
|
||||
Decl *TheDecl;
|
||||
SourceLocation Loc;
|
||||
SourceManager &SM;
|
||||
const char *Message;
|
||||
public:
|
||||
PrettyStackTraceDecl(Decl *theDecl, SourceLocation L,
|
||||
SourceManager &sm, const char *Msg)
|
||||
: TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {}
|
||||
|
||||
virtual void print(llvm::raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
|
||||
/// DeclContext - This is used only as base class of specific decl types that
|
||||
/// can act as declaration contexts. These decls are (only the top classes
|
||||
/// that directly derive from DeclContext are mentioned, not their subclasses):
|
||||
///
|
||||
/// TranslationUnitDecl
|
||||
/// NamespaceDecl
|
||||
/// FunctionDecl
|
||||
/// TagDecl
|
||||
/// ObjCMethodDecl
|
||||
/// ObjCContainerDecl
|
||||
/// ObjCCategoryImplDecl
|
||||
/// ObjCImplementationDecl
|
||||
/// LinkageSpecDecl
|
||||
/// BlockDecl
|
||||
///
|
||||
class DeclContext {
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Decl::Kind 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;
|
||||
|
||||
/// \brief Whether this declaration context also has some external
|
||||
/// storage that contains additional declarations that are visible
|
||||
/// in this context.
|
||||
mutable bool ExternalVisibleStorage : 1;
|
||||
|
||||
/// \brief Pointer to the data structure used to lookup declarations
|
||||
/// within this context, which is a DenseMap<DeclarationName,
|
||||
/// StoredDeclsList>.
|
||||
mutable void* LookupPtr;
|
||||
|
||||
/// FirstDecl - The first declaration stored within this declaration
|
||||
/// context.
|
||||
mutable Decl *FirstDecl;
|
||||
|
||||
/// LastDecl - The last declaration stored within this declaration
|
||||
/// context. FIXME: We could probably cache this value somewhere
|
||||
/// outside of the DeclContext, to reduce the size of DeclContext by
|
||||
/// another pointer.
|
||||
mutable Decl *LastDecl;
|
||||
|
||||
protected:
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), ExternalLexicalStorage(false),
|
||||
ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
|
||||
LastDecl(0) { }
|
||||
|
||||
void DestroyDecls(ASTContext &C);
|
||||
|
||||
public:
|
||||
~DeclContext();
|
||||
|
||||
Decl::Kind getDeclKind() const {
|
||||
return DeclKind;
|
||||
}
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
/// getParent - Returns the containing DeclContext.
|
||||
DeclContext *getParent() {
|
||||
return cast<Decl>(this)->getDeclContext();
|
||||
}
|
||||
const DeclContext *getParent() const {
|
||||
return const_cast<DeclContext*>(this)->getParent();
|
||||
}
|
||||
|
||||
/// getLexicalParent - Returns the containing lexical DeclContext. May be
|
||||
/// different from getParent, e.g.:
|
||||
///
|
||||
/// namespace A {
|
||||
/// struct S;
|
||||
/// }
|
||||
/// struct A::S {}; // getParent() == namespace 'A'
|
||||
/// // getLexicalParent() == translation unit
|
||||
///
|
||||
DeclContext *getLexicalParent() {
|
||||
return cast<Decl>(this)->getLexicalDeclContext();
|
||||
}
|
||||
const DeclContext *getLexicalParent() const {
|
||||
return const_cast<DeclContext*>(this)->getLexicalParent();
|
||||
}
|
||||
|
||||
bool isFunctionOrMethod() const {
|
||||
switch (DeclKind) {
|
||||
case Decl::Block:
|
||||
case Decl::ObjCMethod:
|
||||
return true;
|
||||
default:
|
||||
return DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast;
|
||||
}
|
||||
}
|
||||
|
||||
bool isFileContext() const {
|
||||
return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace;
|
||||
}
|
||||
|
||||
bool isTranslationUnit() const {
|
||||
return DeclKind == Decl::TranslationUnit;
|
||||
}
|
||||
|
||||
bool isRecord() const {
|
||||
return DeclKind >= Decl::RecordFirst && DeclKind <= Decl::RecordLast;
|
||||
}
|
||||
|
||||
bool isNamespace() const {
|
||||
return DeclKind == Decl::Namespace;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this context is dependent on a
|
||||
/// template parameter.
|
||||
bool isDependentContext() const;
|
||||
|
||||
/// isTransparentContext - Determines whether this context is a
|
||||
/// "transparent" context, meaning that the members declared in this
|
||||
/// context are semantically declared in the nearest enclosing
|
||||
/// non-transparent (opaque) context but are lexically declared in
|
||||
/// this context. For example, consider the enumerators of an
|
||||
/// enumeration type:
|
||||
/// @code
|
||||
/// enum E {
|
||||
/// Val1
|
||||
/// };
|
||||
/// @endcode
|
||||
/// Here, E is a transparent context, so its enumerator (Val1) will
|
||||
/// appear (semantically) that it is in the same context of E.
|
||||
/// Examples of transparent contexts include: enumerations (except for
|
||||
/// C++0x scoped enums), C++ linkage specifications, and C++0x
|
||||
/// inline namespaces.
|
||||
bool isTransparentContext() const;
|
||||
|
||||
bool Encloses(DeclContext *DC) const {
|
||||
for (; DC; DC = DC->getParent())
|
||||
if (DC == this)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// getPrimaryContext - There may be many different
|
||||
/// declarations of the same entity (including forward declarations
|
||||
/// of classes, multiple definitions of namespaces, etc.), each with
|
||||
/// a different set of declarations. This routine returns the
|
||||
/// "primary" DeclContext structure, which will contain the
|
||||
/// information needed to perform name lookup into this context.
|
||||
DeclContext *getPrimaryContext();
|
||||
|
||||
/// getLookupContext - Retrieve the innermost non-transparent
|
||||
/// context of this context, which corresponds to the innermost
|
||||
/// location from which name lookup can find the entities in this
|
||||
/// context.
|
||||
DeclContext *getLookupContext();
|
||||
const DeclContext *getLookupContext() const {
|
||||
return const_cast<DeclContext *>(this)->getLookupContext();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the nearest enclosing namespace context.
|
||||
DeclContext *getEnclosingNamespaceContext();
|
||||
const DeclContext *getEnclosingNamespaceContext() const {
|
||||
return const_cast<DeclContext *>(this)->getEnclosingNamespaceContext();
|
||||
}
|
||||
|
||||
/// getNextContext - If this is a DeclContext that may have other
|
||||
/// DeclContexts that are semantically connected but syntactically
|
||||
/// different, such as C++ namespaces, this routine retrieves the
|
||||
/// next DeclContext in the link. Iteration through the chain of
|
||||
/// DeclContexts should begin at the primary DeclContext and
|
||||
/// continue until this function returns NULL. For example, given:
|
||||
/// @code
|
||||
/// namespace N {
|
||||
/// int x;
|
||||
/// }
|
||||
/// namespace N {
|
||||
/// int y;
|
||||
/// }
|
||||
/// @endcode
|
||||
/// The first occurrence of namespace N will be the primary
|
||||
/// DeclContext. Its getNextContext will return the second
|
||||
/// occurrence of namespace N.
|
||||
DeclContext *getNextContext();
|
||||
|
||||
/// decl_iterator - Iterates through the declarations stored
|
||||
/// within this context.
|
||||
class decl_iterator {
|
||||
/// Current - The current declaration.
|
||||
Decl *Current;
|
||||
|
||||
public:
|
||||
typedef Decl* value_type;
|
||||
typedef Decl* reference;
|
||||
typedef Decl* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
decl_iterator() : Current(0) { }
|
||||
explicit decl_iterator(Decl *C) : Current(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
pointer operator->() const { return Current; }
|
||||
|
||||
decl_iterator& operator++() {
|
||||
Current = Current->getNextDeclInContext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
decl_iterator operator++(int) {
|
||||
decl_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(decl_iterator x, decl_iterator y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
friend bool operator!=(decl_iterator x, decl_iterator y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
||||
/// decls_begin/decls_end - Iterate over the declarations stored in
|
||||
/// this context.
|
||||
decl_iterator decls_begin(ASTContext &Context) const;
|
||||
decl_iterator decls_end(ASTContext &Context) const;
|
||||
bool decls_empty(ASTContext &Context) const;
|
||||
|
||||
/// specific_decl_iterator - Iterates over a subrange of
|
||||
/// declarations stored in a DeclContext, providing only those that
|
||||
/// are of type SpecificDecl (or a class derived from it). This
|
||||
/// iterator is used, for example, to provide iteration over just
|
||||
/// the fields within a RecordDecl (with SpecificDecl = FieldDecl).
|
||||
template<typename SpecificDecl>
|
||||
class specific_decl_iterator {
|
||||
/// Current - The current, underlying declaration iterator, which
|
||||
/// will either be NULL or will point to a declaration of
|
||||
/// type SpecificDecl.
|
||||
DeclContext::decl_iterator Current;
|
||||
|
||||
/// SkipToNextDecl - Advances the current position up to the next
|
||||
/// declaration of type SpecificDecl that also meets the criteria
|
||||
/// required by Acceptable.
|
||||
void SkipToNextDecl() {
|
||||
while (*Current && !isa<SpecificDecl>(*Current))
|
||||
++Current;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef SpecificDecl* value_type;
|
||||
typedef SpecificDecl* reference;
|
||||
typedef SpecificDecl* pointer;
|
||||
typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type
|
||||
difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
specific_decl_iterator() : Current() { }
|
||||
|
||||
/// specific_decl_iterator - Construct a new iterator over a
|
||||
/// subset of the declarations the range [C,
|
||||
/// end-of-declarations). If A is non-NULL, it is a pointer to a
|
||||
/// member function of SpecificDecl that should return true for
|
||||
/// all of the SpecificDecl instances that will be in the subset
|
||||
/// of iterators. For example, if you want Objective-C instance
|
||||
/// methods, SpecificDecl will be ObjCMethodDecl and A will be
|
||||
/// &ObjCMethodDecl::isInstanceMethod.
|
||||
explicit specific_decl_iterator(DeclContext::decl_iterator C) : Current(C) {
|
||||
SkipToNextDecl();
|
||||
}
|
||||
|
||||
reference operator*() const { return cast<SpecificDecl>(*Current); }
|
||||
pointer operator->() const { return cast<SpecificDecl>(*Current); }
|
||||
|
||||
specific_decl_iterator& operator++() {
|
||||
++Current;
|
||||
SkipToNextDecl();
|
||||
return *this;
|
||||
}
|
||||
|
||||
specific_decl_iterator operator++(int) {
|
||||
specific_decl_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Iterates over a filtered subrange of declarations stored
|
||||
/// in a DeclContext.
|
||||
///
|
||||
/// This iterator visits only those declarations that are of type
|
||||
/// SpecificDecl (or a class derived from it) and that meet some
|
||||
/// additional run-time criteria. This iterator is used, for
|
||||
/// example, to provide access to the instance methods within an
|
||||
/// Objective-C interface (with SpecificDecl = ObjCMethodDecl and
|
||||
/// Acceptable = ObjCMethodDecl::isInstanceMethod).
|
||||
template<typename SpecificDecl, bool (SpecificDecl::*Acceptable)() const>
|
||||
class filtered_decl_iterator {
|
||||
/// Current - The current, underlying declaration iterator, which
|
||||
/// will either be NULL or will point to a declaration of
|
||||
/// type SpecificDecl.
|
||||
DeclContext::decl_iterator Current;
|
||||
|
||||
/// SkipToNextDecl - Advances the current position up to the next
|
||||
/// declaration of type SpecificDecl that also meets the criteria
|
||||
/// required by Acceptable.
|
||||
void SkipToNextDecl() {
|
||||
while (*Current &&
|
||||
(!isa<SpecificDecl>(*Current) ||
|
||||
(Acceptable && !(cast<SpecificDecl>(*Current)->*Acceptable)())))
|
||||
++Current;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef SpecificDecl* value_type;
|
||||
typedef SpecificDecl* reference;
|
||||
typedef SpecificDecl* pointer;
|
||||
typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type
|
||||
difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
filtered_decl_iterator() : Current() { }
|
||||
|
||||
/// specific_decl_iterator - Construct a new iterator over a
|
||||
/// subset of the declarations the range [C,
|
||||
/// end-of-declarations). If A is non-NULL, it is a pointer to a
|
||||
/// member function of SpecificDecl that should return true for
|
||||
/// all of the SpecificDecl instances that will be in the subset
|
||||
/// of iterators. For example, if you want Objective-C instance
|
||||
/// methods, SpecificDecl will be ObjCMethodDecl and A will be
|
||||
/// &ObjCMethodDecl::isInstanceMethod.
|
||||
explicit filtered_decl_iterator(DeclContext::decl_iterator C) : Current(C) {
|
||||
SkipToNextDecl();
|
||||
}
|
||||
|
||||
reference operator*() const { return cast<SpecificDecl>(*Current); }
|
||||
pointer operator->() const { return cast<SpecificDecl>(*Current); }
|
||||
|
||||
filtered_decl_iterator& operator++() {
|
||||
++Current;
|
||||
SkipToNextDecl();
|
||||
return *this;
|
||||
}
|
||||
|
||||
filtered_decl_iterator operator++(int) {
|
||||
filtered_decl_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Add the declaration D into this context.
|
||||
///
|
||||
/// This routine should be invoked when the declaration D has first
|
||||
/// been declared, to place D into the context where it was
|
||||
/// (lexically) defined. Every declaration must be added to one
|
||||
/// (and only one!) context, where it can be visited via
|
||||
/// [decls_begin(), decls_end()). Once a declaration has been added
|
||||
/// to its lexical context, the corresponding DeclContext owns the
|
||||
/// declaration.
|
||||
///
|
||||
/// If D is also a NamedDecl, it will be made visible within its
|
||||
/// semantic context via makeDeclVisibleInContext.
|
||||
void addDecl(ASTContext &Context, Decl *D);
|
||||
|
||||
/// lookup_iterator - An iterator that provides access to the results
|
||||
/// of looking up a name within this context.
|
||||
typedef NamedDecl **lookup_iterator;
|
||||
|
||||
/// lookup_const_iterator - An iterator that provides non-mutable
|
||||
/// access to the results of lookup up a name within this context.
|
||||
typedef NamedDecl * const * lookup_const_iterator;
|
||||
|
||||
typedef std::pair<lookup_iterator, lookup_iterator> lookup_result;
|
||||
typedef std::pair<lookup_const_iterator, lookup_const_iterator>
|
||||
lookup_const_result;
|
||||
|
||||
/// lookup - Find the declarations (if any) with the given Name in
|
||||
/// this context. Returns a range of iterators that contains all of
|
||||
/// the declarations with this name, with object, function, member,
|
||||
/// and enumerator names preceding any tag name. Note that this
|
||||
/// routine will not look into parent contexts.
|
||||
lookup_result lookup(ASTContext &Context, DeclarationName Name);
|
||||
lookup_const_result lookup(ASTContext &Context, DeclarationName Name) const;
|
||||
|
||||
/// @brief Makes a declaration visible within this context.
|
||||
///
|
||||
/// This routine makes the declaration D visible to name lookup
|
||||
/// within this context and, if this is a transparent context,
|
||||
/// within its parent contexts up to the first enclosing
|
||||
/// non-transparent context. Making a declaration visible within a
|
||||
/// context does not transfer ownership of a declaration, and a
|
||||
/// declaration can be visible in many contexts that aren't its
|
||||
/// lexical context.
|
||||
///
|
||||
/// If D is a redeclaration of an existing declaration that is
|
||||
/// visible from this context, as determined by
|
||||
/// NamedDecl::declarationReplaces, the previous declaration will be
|
||||
/// replaced with D.
|
||||
void makeDeclVisibleInContext(ASTContext &Context, NamedDecl *D);
|
||||
|
||||
/// udir_iterator - Iterates through the using-directives stored
|
||||
/// within this context.
|
||||
typedef UsingDirectiveDecl * const * udir_iterator;
|
||||
|
||||
typedef std::pair<udir_iterator, udir_iterator> udir_iterator_range;
|
||||
|
||||
udir_iterator_range getUsingDirectives(ASTContext &Context) const;
|
||||
|
||||
udir_iterator using_directives_begin(ASTContext &Context) const {
|
||||
return getUsingDirectives(Context).first;
|
||||
}
|
||||
|
||||
udir_iterator using_directives_end(ASTContext &Context) const {
|
||||
return getUsingDirectives(Context).second;
|
||||
}
|
||||
|
||||
// Low-level accessors
|
||||
|
||||
/// \brief Retrieve the internal representation of the lookup structure.
|
||||
void* getLookupPtr() const { return LookupPtr; }
|
||||
|
||||
/// \brief Whether this DeclContext has external storage containing
|
||||
/// additional declarations that are lexically in this context.
|
||||
bool hasExternalLexicalStorage() const { return ExternalLexicalStorage; }
|
||||
|
||||
/// \brief State whether this DeclContext has external storage for
|
||||
/// declarations lexically in this context.
|
||||
void setHasExternalLexicalStorage(bool ES = true) {
|
||||
ExternalLexicalStorage = ES;
|
||||
}
|
||||
|
||||
/// \brief Whether this DeclContext has external storage containing
|
||||
/// additional declarations that are visible in this context.
|
||||
bool hasExternalVisibleStorage() const { return ExternalVisibleStorage; }
|
||||
|
||||
/// \brief State whether this DeclContext has external storage for
|
||||
/// declarations visible in this context.
|
||||
void setHasExternalVisibleStorage(bool ES = true) {
|
||||
ExternalVisibleStorage = ES;
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D);
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
#define DECL_CONTEXT(Name) \
|
||||
static bool classof(const Name##Decl *D) { return true; }
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
|
||||
private:
|
||||
void LoadLexicalDeclsFromExternalStorage(ASTContext &Context) const;
|
||||
void LoadVisibleDeclsFromExternalStorage(ASTContext &Context) const;
|
||||
|
||||
void buildLookup(ASTContext &Context, DeclContext *DCtx);
|
||||
void makeDeclVisibleInContextImpl(ASTContext &Context, NamedDecl *D);
|
||||
};
|
||||
|
||||
inline bool Decl::isTemplateParameter() const {
|
||||
return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm;
|
||||
}
|
||||
|
||||
inline bool Decl::isDefinedOutsideFunctionOrMethod() const {
|
||||
if (getDeclContext())
|
||||
return !getDeclContext()->getLookupContext()->isFunctionOrMethod();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end clang.
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Implement a isa_impl_wrap specialization to check whether a DeclContext is
|
||||
/// a specific Decl.
|
||||
template<class ToTy>
|
||||
struct isa_impl_wrap<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {
|
||||
static bool doit(const ::clang::DeclContext &Val) {
|
||||
return ToTy::classof(::clang::Decl::castFromDeclContext(&Val));
|
||||
}
|
||||
};
|
||||
template<class ToTy>
|
||||
struct isa_impl_wrap<ToTy, ::clang::DeclContext, ::clang::DeclContext>
|
||||
: public isa_impl_wrap<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {};
|
||||
|
||||
/// Implement cast_convert_val for Decl -> DeclContext conversions.
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> {
|
||||
static ::clang::DeclContext &doit(const FromTy &Val) {
|
||||
return *FromTy::castToDeclContext(&Val);
|
||||
}
|
||||
};
|
||||
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> {
|
||||
static ::clang::DeclContext *doit(const FromTy *Val) {
|
||||
return FromTy::castToDeclContext(Val);
|
||||
}
|
||||
};
|
||||
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> {
|
||||
static const ::clang::DeclContext &doit(const FromTy &Val) {
|
||||
return *FromTy::castToDeclContext(&Val);
|
||||
}
|
||||
};
|
||||
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> {
|
||||
static const ::clang::DeclContext *doit(const FromTy *Val) {
|
||||
return FromTy::castToDeclContext(Val);
|
||||
}
|
||||
};
|
||||
|
||||
/// Implement cast_convert_val for DeclContext -> Decl conversions.
|
||||
template<class ToTy>
|
||||
struct cast_convert_val<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {
|
||||
static ToTy &doit(const ::clang::DeclContext &Val) {
|
||||
return *reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(&Val));
|
||||
}
|
||||
};
|
||||
template<class ToTy>
|
||||
struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext>
|
||||
: public cast_convert_val<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {};
|
||||
|
||||
template<class ToTy>
|
||||
struct cast_convert_val<ToTy,
|
||||
const ::clang::DeclContext*, const ::clang::DeclContext*> {
|
||||
static ToTy *doit(const ::clang::DeclContext *Val) {
|
||||
return reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(Val));
|
||||
}
|
||||
};
|
||||
template<class ToTy>
|
||||
struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*>
|
||||
: public cast_convert_val<ToTy,
|
||||
const ::clang::DeclContext*,const ::clang::DeclContext*> {};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
1073
include/clang/AST/DeclCXX.h
Normal file
1073
include/clang/AST/DeclCXX.h
Normal file
File diff suppressed because it is too large
Load Diff
220
include/clang/AST/DeclContextInternals.h
Normal file
220
include/clang/AST/DeclContextInternals.h
Normal file
@ -0,0 +1,220 @@
|
||||
//===-- DeclContextInternals.h - DeclContext Representation -----*- 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 data structures used in the implementation
|
||||
// of DeclContext.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
|
||||
#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// StoredDeclsList - This is an array of decls optimized a common case of only
|
||||
/// containing one entry.
|
||||
struct StoredDeclsList {
|
||||
/// The kind of data encoded in this list.
|
||||
enum DataKind {
|
||||
/// \brief The data is a NamedDecl*.
|
||||
DK_Decl = 0,
|
||||
/// \brief The data is a declaration ID (an unsigned value),
|
||||
/// shifted left by 2 bits.
|
||||
DK_DeclID = 1,
|
||||
/// \brief The data is a pointer to a vector (of type VectorTy)
|
||||
/// that contains declarations.
|
||||
DK_Decl_Vector = 2,
|
||||
/// \brief The data is a pointer to a vector (of type VectorTy)
|
||||
/// that contains declaration ID.
|
||||
DK_ID_Vector = 3
|
||||
};
|
||||
|
||||
/// VectorTy - When in vector form, this is what the Data pointer points to.
|
||||
typedef llvm::SmallVector<uintptr_t, 4> VectorTy;
|
||||
|
||||
/// \brief The stored data, which will be either a declaration ID, a
|
||||
/// pointer to a NamedDecl, or a pointer to a vector.
|
||||
uintptr_t Data;
|
||||
|
||||
public:
|
||||
StoredDeclsList() : Data(0) {}
|
||||
|
||||
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
|
||||
if (VectorTy *RHSVec = RHS.getAsVector()) {
|
||||
VectorTy *New = new VectorTy(*RHSVec);
|
||||
Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
|
||||
}
|
||||
}
|
||||
|
||||
~StoredDeclsList() {
|
||||
// If this is a vector-form, free the vector.
|
||||
if (VectorTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
}
|
||||
|
||||
StoredDeclsList &operator=(const StoredDeclsList &RHS) {
|
||||
if (VectorTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
Data = RHS.Data;
|
||||
if (VectorTy *RHSVec = RHS.getAsVector()) {
|
||||
VectorTy *New = new VectorTy(*RHSVec);
|
||||
Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isNull() const { return (Data & ~0x03) == 0; }
|
||||
|
||||
NamedDecl *getAsDecl() const {
|
||||
if ((Data & 0x03) != DK_Decl)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<NamedDecl *>(Data & ~0x03);
|
||||
}
|
||||
|
||||
VectorTy *getAsVector() const {
|
||||
if ((Data & 0x03) != DK_ID_Vector && (Data & 0x03) != DK_Decl_Vector)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<VectorTy *>(Data & ~0x03);
|
||||
}
|
||||
|
||||
void setOnlyValue(NamedDecl *ND) {
|
||||
assert(!getAsVector() && "Not inline");
|
||||
Data = reinterpret_cast<uintptr_t>(ND);
|
||||
}
|
||||
|
||||
void setFromDeclIDs(const llvm::SmallVectorImpl<unsigned> &Vec) {
|
||||
if (Vec.size() > 1) {
|
||||
VectorTy *Vector = getAsVector();
|
||||
if (!Vector) {
|
||||
Vector = new VectorTy;
|
||||
Data = reinterpret_cast<uintptr_t>(Vector) | DK_ID_Vector;
|
||||
}
|
||||
|
||||
Vector->resize(Vec.size());
|
||||
std::copy(Vec.begin(), Vec.end(), Vector->begin());
|
||||
return;
|
||||
}
|
||||
|
||||
if (VectorTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
|
||||
if (Vec.empty())
|
||||
Data = 0;
|
||||
else
|
||||
Data = (Vec[0] << 2) | DK_DeclID;
|
||||
}
|
||||
|
||||
/// \brief Force the stored declarations list to contain actual
|
||||
/// declarations.
|
||||
///
|
||||
/// This routine will resolve any declaration IDs for declarations
|
||||
/// that may not yet have been loaded from external storage.
|
||||
void materializeDecls(ASTContext &Context);
|
||||
|
||||
bool hasDeclarationIDs() const {
|
||||
DataKind DK = (DataKind)(Data & 0x03);
|
||||
return DK == DK_DeclID || DK == DK_ID_Vector;
|
||||
}
|
||||
|
||||
/// getLookupResult - Return an array of all the decls that this list
|
||||
/// represents.
|
||||
DeclContext::lookup_result getLookupResult(ASTContext &Context) {
|
||||
if (isNull())
|
||||
return DeclContext::lookup_result(0, 0);
|
||||
|
||||
if (hasDeclarationIDs())
|
||||
materializeDecls(Context);
|
||||
|
||||
// If we have a single NamedDecl, return it.
|
||||
if (getAsDecl()) {
|
||||
assert(!isNull() && "Empty list isn't allowed");
|
||||
|
||||
// Data is a raw pointer to a NamedDecl*, return it.
|
||||
void *Ptr = &Data;
|
||||
return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1);
|
||||
}
|
||||
|
||||
assert(getAsVector() && "Must have a vector at this point");
|
||||
VectorTy &Vector = *getAsVector();
|
||||
|
||||
// Otherwise, we have a range result.
|
||||
return DeclContext::lookup_result((NamedDecl **)&Vector[0],
|
||||
(NamedDecl **)&Vector[0]+Vector.size());
|
||||
}
|
||||
|
||||
/// HandleRedeclaration - If this is a redeclaration of an existing decl,
|
||||
/// replace the old one with D and return true. Otherwise return false.
|
||||
bool HandleRedeclaration(ASTContext &Context, NamedDecl *D) {
|
||||
if (hasDeclarationIDs())
|
||||
materializeDecls(Context);
|
||||
|
||||
// Most decls only have one entry in their list, special case it.
|
||||
if (NamedDecl *OldD = getAsDecl()) {
|
||||
if (!D->declarationReplaces(OldD))
|
||||
return false;
|
||||
setOnlyValue(D);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine if this declaration is actually a redeclaration.
|
||||
VectorTy &Vec = *getAsVector();
|
||||
for (VectorTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
|
||||
OD != ODEnd; ++OD) {
|
||||
NamedDecl *OldD = reinterpret_cast<NamedDecl *>(*OD);
|
||||
if (D->declarationReplaces(OldD)) {
|
||||
*OD = reinterpret_cast<uintptr_t>(D);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// AddSubsequentDecl - This is called on the second and later decl when it is
|
||||
/// not a redeclaration to merge it into the appropriate place in our list.
|
||||
///
|
||||
void AddSubsequentDecl(NamedDecl *D) {
|
||||
assert(!hasDeclarationIDs() && "Must materialize before adding decls");
|
||||
|
||||
// If this is the second decl added to the list, convert this to vector
|
||||
// form.
|
||||
if (NamedDecl *OldD = getAsDecl()) {
|
||||
VectorTy *VT = new VectorTy();
|
||||
VT->push_back(reinterpret_cast<uintptr_t>(OldD));
|
||||
Data = reinterpret_cast<uintptr_t>(VT) | DK_Decl_Vector;
|
||||
}
|
||||
|
||||
VectorTy &Vec = *getAsVector();
|
||||
if (isa<UsingDirectiveDecl>(D) ||
|
||||
D->getIdentifierNamespace() == Decl::IDNS_Tag)
|
||||
Vec.push_back(reinterpret_cast<uintptr_t>(D));
|
||||
else if (reinterpret_cast<NamedDecl *>(Vec.back())
|
||||
->getIdentifierNamespace() == Decl::IDNS_Tag) {
|
||||
uintptr_t TagD = Vec.back();
|
||||
Vec.back() = reinterpret_cast<uintptr_t>(D);
|
||||
Vec.push_back(TagD);
|
||||
} else
|
||||
Vec.push_back(reinterpret_cast<uintptr_t>(D));
|
||||
}
|
||||
};
|
||||
|
||||
typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap;
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
152
include/clang/AST/DeclGroup.h
Normal file
152
include/clang/AST/DeclGroup.h
Normal file
@ -0,0 +1,152 @@
|
||||
//===--- DeclGroup.h - Classes for representing groups of Decls -*- 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 DeclGroup, DeclGroupRef, and OwningDeclGroup classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLGROUP_H
|
||||
#define LLVM_CLANG_AST_DECLGROUP_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class DeclGroup;
|
||||
class DeclGroupIterator;
|
||||
|
||||
class DeclGroup {
|
||||
// FIXME: Include a TypeSpecifier object.
|
||||
unsigned NumDecls;
|
||||
|
||||
private:
|
||||
DeclGroup() : NumDecls(0) {}
|
||||
DeclGroup(unsigned numdecls, Decl** decls);
|
||||
|
||||
public:
|
||||
static DeclGroup *Create(ASTContext &C, Decl **Decls, unsigned NumDecls);
|
||||
void Destroy(ASTContext& C);
|
||||
|
||||
unsigned size() const { return NumDecls; }
|
||||
|
||||
Decl*& operator[](unsigned i) {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return *((Decl**) (this+1));
|
||||
}
|
||||
|
||||
Decl* const& operator[](unsigned i) const {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return *((Decl* const*) (this+1));
|
||||
}
|
||||
};
|
||||
|
||||
class DeclGroupRef {
|
||||
// Note this is not a PointerIntPair because we need the address of the
|
||||
// non-group case to be valid as a Decl** for iteration.
|
||||
enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 };
|
||||
Decl* D;
|
||||
|
||||
Kind getKind() const {
|
||||
return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask);
|
||||
}
|
||||
|
||||
public:
|
||||
DeclGroupRef() : D(0) {}
|
||||
|
||||
explicit DeclGroupRef(Decl* d) : D(d) {}
|
||||
explicit DeclGroupRef(DeclGroup* dg)
|
||||
: D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {}
|
||||
|
||||
static DeclGroupRef Create(ASTContext &C, Decl **Decls, unsigned NumDecls) {
|
||||
if (NumDecls == 0)
|
||||
return DeclGroupRef();
|
||||
if (NumDecls == 1)
|
||||
return DeclGroupRef(Decls[0]);
|
||||
return DeclGroupRef(DeclGroup::Create(C, Decls, NumDecls));
|
||||
}
|
||||
|
||||
typedef Decl** iterator;
|
||||
typedef Decl* const * const_iterator;
|
||||
|
||||
bool isNull() const { return D == 0; }
|
||||
bool isSingleDecl() const { return getKind() == SingleDeclKind; }
|
||||
bool isDeclGroup() const { return getKind() == DeclGroupKind; }
|
||||
|
||||
Decl *getSingleDecl() {
|
||||
assert(isSingleDecl() && "Isn't a declgroup");
|
||||
return D;
|
||||
}
|
||||
const Decl *getSingleDecl() const {
|
||||
return const_cast<DeclGroupRef*>(this)->getSingleDecl();
|
||||
}
|
||||
|
||||
DeclGroup &getDeclGroup() {
|
||||
assert(isDeclGroup() && "Isn't a declgroup");
|
||||
return *((DeclGroup*)(reinterpret_cast<uintptr_t>(D) & ~Mask));
|
||||
}
|
||||
const DeclGroup &getDeclGroup() const {
|
||||
return const_cast<DeclGroupRef*>(this)->getDeclGroup();
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
if (isSingleDecl())
|
||||
return D ? &D : 0;
|
||||
return &getDeclGroup()[0];
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
if (isSingleDecl())
|
||||
return D ? &D+1 : 0;
|
||||
DeclGroup &G = getDeclGroup();
|
||||
return &G[0] + G.size();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if (isSingleDecl())
|
||||
return D ? &D : 0;
|
||||
return &getDeclGroup()[0];
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
if (isSingleDecl())
|
||||
return D ? &D+1 : 0;
|
||||
const DeclGroup &G = getDeclGroup();
|
||||
return &G[0] + G.size();
|
||||
}
|
||||
|
||||
void *getAsOpaquePtr() const { return D; }
|
||||
static DeclGroupRef getFromOpaquePtr(void *Ptr) {
|
||||
DeclGroupRef X;
|
||||
X.D = static_cast<Decl*>(Ptr);
|
||||
return X;
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
namespace llvm {
|
||||
// DeclGroupRef is "like a pointer", implement PointerLikeTypeTraits.
|
||||
template <typename T>
|
||||
class PointerLikeTypeTraits;
|
||||
template <>
|
||||
class PointerLikeTypeTraits<clang::DeclGroupRef> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(clang::DeclGroupRef P) {
|
||||
return P.getAsOpaquePtr();
|
||||
}
|
||||
static inline clang::DeclGroupRef getFromVoidPointer(void *P) {
|
||||
return clang::DeclGroupRef::getFromOpaquePtr(P);
|
||||
}
|
||||
enum { NumLowBitsAvailable = 0 };
|
||||
};
|
||||
}
|
||||
#endif
|
161
include/clang/AST/DeclNodes.def
Normal file
161
include/clang/AST/DeclNodes.def
Normal file
@ -0,0 +1,161 @@
|
||||
//===-- DeclNodes.def - Metadata about Decl AST nodes -----------*- 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 declaration nodes within the AST. The
|
||||
// description of the declaration nodes uses six macros:
|
||||
//
|
||||
// DECL(Derived, Base) describes a normal declaration type Derived
|
||||
// and specifies its base class. Note that Derived should not have
|
||||
// the Decl suffix on it, while Base should.
|
||||
//
|
||||
// LAST_DECL(Derived, Base) is like DECL, but is used for the last
|
||||
// declaration in the list.
|
||||
//
|
||||
// ABSTRACT_DECL(Derived, Base) describes an abstract class that is
|
||||
// used to specify a classification of declarations. For example,
|
||||
// TagDecl is an abstract class used to describe the various kinds of
|
||||
// "tag" declarations (unions, structs, classes, enums).
|
||||
//
|
||||
// DECL_CONTEXT(Decl) specifies that Decl is a kind of declaration
|
||||
// that is also a DeclContext.
|
||||
//
|
||||
// LAST_DECL_CONTEXT(Decl) is like DECL_CONTEXT, but is used for the
|
||||
// last declaration context.
|
||||
//
|
||||
// DECL_RANGE(CommonBase, Start, End) specifies a range of
|
||||
// declaration values that have a common (potentially indirect) base
|
||||
// class.
|
||||
//
|
||||
// LAST_DECL_RANGE(CommonBase, Start, End) is like DECL_RANGE, but is
|
||||
// used for the last declaration range.
|
||||
//
|
||||
// Note that, due to the use of ranges, the order of the these
|
||||
// declarations is significant. A declaration should be listed under
|
||||
// its base class.
|
||||
// ===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DECL
|
||||
# define DECL(Derived, Base)
|
||||
#endif
|
||||
|
||||
#ifndef LAST_DECL
|
||||
# define LAST_DECL(Derived, Base) DECL(Derived, Base)
|
||||
#endif
|
||||
|
||||
#ifndef ABSTRACT_DECL
|
||||
# define ABSTRACT_DECL(Derived, Base)
|
||||
#endif
|
||||
|
||||
#ifndef DECL_CONTEXT
|
||||
# define DECL_CONTEXT(Decl)
|
||||
#endif
|
||||
|
||||
#ifndef DECL_CONTEXT_BASE
|
||||
# define DECL_CONTEXT_BASE(Decl) DECL_CONTEXT(Decl)
|
||||
#endif
|
||||
|
||||
#ifndef LAST_DECL_CONTEXT
|
||||
# define LAST_DECL_CONTEXT(Decl) DECL_CONTEXT(Decl)
|
||||
#endif
|
||||
|
||||
#ifndef DECL_RANGE
|
||||
# define DECL_RANGE(CommonBase, Start, End)
|
||||
#endif
|
||||
|
||||
#ifndef LAST_DECL_RANGE
|
||||
# define LAST_DECL_RANGE(CommonBase, Start, End) \
|
||||
DECL_RANGE(CommonBase, Start, End)
|
||||
#endif
|
||||
|
||||
DECL(TranslationUnit, Decl)
|
||||
ABSTRACT_DECL(Named, Decl)
|
||||
DECL(OverloadedFunction, NamedDecl)
|
||||
DECL(Namespace, NamedDecl)
|
||||
DECL(UsingDirective, NamedDecl)
|
||||
DECL(NamespaceAlias, NamedDecl)
|
||||
ABSTRACT_DECL(Type, NamedDecl)
|
||||
DECL(Typedef, TypeDecl)
|
||||
ABSTRACT_DECL(Tag, TypeDecl)
|
||||
DECL(Enum, TagDecl)
|
||||
DECL(Record, TagDecl)
|
||||
DECL(CXXRecord, RecordDecl)
|
||||
DECL(ClassTemplateSpecialization, CXXRecordDecl)
|
||||
DECL(ClassTemplatePartialSpecialization,
|
||||
ClassTemplateSpecializationDecl)
|
||||
DECL(TemplateTypeParm, TypeDecl)
|
||||
ABSTRACT_DECL(Value, NamedDecl)
|
||||
DECL(EnumConstant, ValueDecl)
|
||||
DECL(Function, ValueDecl)
|
||||
DECL(CXXMethod, FunctionDecl)
|
||||
DECL(CXXConstructor, CXXMethodDecl)
|
||||
DECL(CXXDestructor, CXXMethodDecl)
|
||||
DECL(CXXConversion, CXXMethodDecl)
|
||||
DECL(Field, ValueDecl)
|
||||
DECL(ObjCIvar, FieldDecl)
|
||||
DECL(ObjCAtDefsField, FieldDecl)
|
||||
DECL(Var, ValueDecl)
|
||||
DECL(ImplicitParam, VarDecl)
|
||||
DECL(ParmVar, VarDecl)
|
||||
DECL(OriginalParmVar, ParmVarDecl)
|
||||
DECL(NonTypeTemplateParm, VarDecl)
|
||||
DECL(Template, NamedDecl)
|
||||
DECL(FunctionTemplate, TemplateDecl)
|
||||
DECL(ClassTemplate, TemplateDecl)
|
||||
DECL(TemplateTemplateParm, TemplateDecl)
|
||||
DECL(ObjCMethod, NamedDecl)
|
||||
DECL(ObjCContainer, NamedDecl)
|
||||
DECL(ObjCCategory, ObjCContainerDecl)
|
||||
DECL(ObjCProtocol, ObjCContainerDecl)
|
||||
DECL(ObjCInterface, ObjCContainerDecl)
|
||||
DECL(ObjCProperty, NamedDecl)
|
||||
DECL(ObjCCompatibleAlias, NamedDecl)
|
||||
ABSTRACT_DECL(ObjCImpl, NamedDecl)
|
||||
DECL(ObjCCategoryImpl, ObjCImplDecl)
|
||||
DECL(ObjCImplementation, ObjCImplDecl)
|
||||
DECL(LinkageSpec, Decl)
|
||||
DECL(ObjCPropertyImpl, Decl)
|
||||
DECL(ObjCForwardProtocol, Decl)
|
||||
DECL(ObjCClass, Decl)
|
||||
DECL(FileScopeAsm, Decl)
|
||||
DECL(StaticAssert, Decl)
|
||||
LAST_DECL(Block, Decl)
|
||||
|
||||
// Declaration contexts. DECL_CONTEXT_BASE indicates that it has subclasses.
|
||||
DECL_CONTEXT(TranslationUnit)
|
||||
DECL_CONTEXT(Namespace)
|
||||
DECL_CONTEXT(LinkageSpec)
|
||||
DECL_CONTEXT(ObjCMethod)
|
||||
DECL_CONTEXT(ObjCCategoryImpl)
|
||||
DECL_CONTEXT(ObjCImplementation)
|
||||
DECL_CONTEXT_BASE(Tag)
|
||||
DECL_CONTEXT_BASE(Function)
|
||||
DECL_CONTEXT_BASE(ObjCContainer)
|
||||
LAST_DECL_CONTEXT(Block)
|
||||
|
||||
// Declaration ranges
|
||||
DECL_RANGE(Named, OverloadedFunction, ObjCImplementation)
|
||||
DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface)
|
||||
DECL_RANGE(Field, Field, ObjCAtDefsField)
|
||||
DECL_RANGE(Type, Typedef, TemplateTypeParm)
|
||||
DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization)
|
||||
DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization)
|
||||
DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
|
||||
DECL_RANGE(Function, Function, CXXConversion)
|
||||
DECL_RANGE(Template, Template, TemplateTemplateParm)
|
||||
DECL_RANGE(ObjCImpl, ObjCCategoryImpl, ObjCImplementation)
|
||||
LAST_DECL_RANGE(Var, Var, NonTypeTemplateParm)
|
||||
|
||||
#undef LAST_DECL_RANGE
|
||||
#undef DECL_RANGE
|
||||
#undef LAST_DECL_CONTEXT
|
||||
#undef DECL_CONTEXT_BASE
|
||||
#undef DECL_CONTEXT
|
||||
#undef ABSTRACT_DECL
|
||||
#undef LAST_DECL
|
||||
#undef DECL
|
1224
include/clang/AST/DeclObjC.h
Normal file
1224
include/clang/AST/DeclObjC.h
Normal file
File diff suppressed because it is too large
Load Diff
859
include/clang/AST/DeclTemplate.h
Normal file
859
include/clang/AST/DeclTemplate.h
Normal file
@ -0,0 +1,859 @@
|
||||
//===-- DeclTemplate.h - Classes for representing C++ templates -*- 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 C++ template declaration subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLTEMPLATE_H
|
||||
#define LLVM_CLANG_AST_DECLTEMPLATE_H
|
||||
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class TemplateParameterList;
|
||||
class TemplateDecl;
|
||||
class FunctionTemplateDecl;
|
||||
class ClassTemplateDecl;
|
||||
class ClassTemplatePartialSpecializationDecl;
|
||||
class TemplateTypeParmDecl;
|
||||
class NonTypeTemplateParmDecl;
|
||||
class TemplateTemplateParmDecl;
|
||||
|
||||
/// TemplateParameterList - Stores a list of template parameters for a
|
||||
/// TemplateDecl and its derived classes.
|
||||
class TemplateParameterList {
|
||||
/// The location of the 'template' keyword.
|
||||
SourceLocation TemplateLoc;
|
||||
|
||||
/// The locations of the '<' and '>' angle brackets.
|
||||
SourceLocation LAngleLoc, RAngleLoc;
|
||||
|
||||
/// The number of template parameters in this template
|
||||
/// parameter list.
|
||||
unsigned NumParams;
|
||||
|
||||
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
|
||||
Decl **Params, unsigned NumParams,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
public:
|
||||
static TemplateParameterList *Create(ASTContext &C,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
Decl **Params,
|
||||
unsigned NumParams,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
/// iterator - Iterates through the template parameters in this list.
|
||||
typedef Decl** iterator;
|
||||
|
||||
/// const_iterator - Iterates through the template parameters in this list.
|
||||
typedef Decl* const* const_iterator;
|
||||
|
||||
iterator begin() { return reinterpret_cast<Decl **>(this + 1); }
|
||||
const_iterator begin() const {
|
||||
return reinterpret_cast<Decl * const *>(this + 1);
|
||||
}
|
||||
iterator end() { return begin() + NumParams; }
|
||||
const_iterator end() const { return begin() + NumParams; }
|
||||
|
||||
unsigned size() const { return NumParams; }
|
||||
|
||||
const Decl* getParam(unsigned Idx) const {
|
||||
assert(Idx < size() && "Template parameter index out-of-range");
|
||||
return begin()[Idx];
|
||||
}
|
||||
|
||||
/// \btief 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.
|
||||
unsigned getMinRequiredArguments() const;
|
||||
|
||||
SourceLocation getTemplateLoc() const { return TemplateLoc; }
|
||||
SourceLocation getLAngleLoc() const { return LAngleLoc; }
|
||||
SourceLocation getRAngleLoc() const { return RAngleLoc; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(TemplateLoc, RAngleLoc);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Kinds of Templates
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// TemplateDecl - The base class of all kinds of template declarations (e.g.,
|
||||
/// class, function, etc.). The TemplateDecl class stores the list of template
|
||||
/// parameters and a reference to the templated scoped declaration: the
|
||||
/// underlying AST node.
|
||||
class TemplateDecl : public NamedDecl {
|
||||
protected:
|
||||
// This is probably never used.
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0)
|
||||
{ }
|
||||
|
||||
// Construct a template decl with the given name and parameters.
|
||||
// Used when there is not templated element (tt-params, alias?).
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(Params)
|
||||
{ }
|
||||
|
||||
// Construct a template decl with name, parameters, and templated element.
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params,
|
||||
NamedDecl *Decl)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl),
|
||||
TemplateParams(Params) { }
|
||||
public:
|
||||
~TemplateDecl();
|
||||
|
||||
/// Get the list of template parameters
|
||||
TemplateParameterList *getTemplateParameters() const {
|
||||
return TemplateParams;
|
||||
}
|
||||
|
||||
/// Get the underlying, templated declaration.
|
||||
NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= TemplateFirst && D->getKind() <= TemplateLast;
|
||||
}
|
||||
static bool classof(const TemplateDecl *D) { return true; }
|
||||
static bool classof(const FunctionTemplateDecl *D) { return true; }
|
||||
static bool classof(const ClassTemplateDecl *D) { return true; }
|
||||
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
NamedDecl *TemplatedDecl;
|
||||
TemplateParameterList* TemplateParams;
|
||||
};
|
||||
|
||||
/// Declaration of a template function.
|
||||
class FunctionTemplateDecl : public TemplateDecl {
|
||||
protected:
|
||||
FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { }
|
||||
public:
|
||||
/// Get the underling function declaration of the template.
|
||||
FunctionDecl *getTemplatedDecl() const {
|
||||
return static_cast<FunctionDecl*>(TemplatedDecl);
|
||||
}
|
||||
|
||||
/// Create a template function node.
|
||||
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,
|
||||
DeclarationName Name,
|
||||
TemplateParameterList *Params,
|
||||
NamedDecl *Decl);
|
||||
|
||||
// Implement isa/cast/dyncast support
|
||||
static bool classof(const Decl *D)
|
||||
{ return D->getKind() == FunctionTemplate; }
|
||||
static bool classof(const FunctionTemplateDecl *D)
|
||||
{ return true; }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Kinds of Template Parameters
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// The TemplateParmPosition class defines the position of a template parameter
|
||||
/// within a template parameter list. Because template parameter can be listed
|
||||
/// sequentially for out-of-line template members, each template parameter is
|
||||
/// given a Depth - the nesting of template parameter scopes - and a Position -
|
||||
/// the occurrence within the parameter list.
|
||||
/// This class is inheritedly privately by different kinds of template
|
||||
/// parameters and is not part of the Decl hierarchy. Just a facility.
|
||||
class TemplateParmPosition
|
||||
{
|
||||
protected:
|
||||
// FIXME: This should probably never be called, but it's here as
|
||||
TemplateParmPosition()
|
||||
: Depth(0), Position(0)
|
||||
{ /* assert(0 && "Cannot create positionless template parameter"); */ }
|
||||
|
||||
TemplateParmPosition(unsigned D, unsigned P)
|
||||
: Depth(D), Position(P)
|
||||
{ }
|
||||
|
||||
// FIXME: These probably don't need to be ints. int:5 for depth, int:8 for
|
||||
// position? Maybe?
|
||||
unsigned Depth;
|
||||
unsigned Position;
|
||||
|
||||
public:
|
||||
/// Get the nesting depth of the template parameter.
|
||||
unsigned getDepth() const { return Depth; }
|
||||
|
||||
/// Get the position of the template parameter within its parameter list.
|
||||
unsigned getPosition() const { return Position; }
|
||||
};
|
||||
|
||||
/// TemplateTypeParmDecl - Declaration of a template type parameter,
|
||||
/// e.g., "T" in
|
||||
/// @code
|
||||
/// template<typename T> class vector;
|
||||
/// @endcode
|
||||
class TemplateTypeParmDecl : public TypeDecl {
|
||||
/// \brief Whether this template type parameter was declaration with
|
||||
/// the 'typename' keyword. If false, it was declared with the
|
||||
/// 'class' keyword.
|
||||
bool Typename : 1;
|
||||
|
||||
/// \brief Whether this template type parameter inherited its
|
||||
/// default argument.
|
||||
bool InheritedDefault : 1;
|
||||
|
||||
/// \brief The location of the default argument, if any.
|
||||
SourceLocation DefaultArgumentLoc;
|
||||
|
||||
/// \brief The default template argument, if any.
|
||||
QualType DefaultArgument;
|
||||
|
||||
TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
|
||||
bool Typename, QualType Type)
|
||||
: TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
|
||||
InheritedDefault(false), DefaultArgument() {
|
||||
TypeForDecl = Type.getTypePtr();
|
||||
}
|
||||
|
||||
public:
|
||||
static TemplateTypeParmDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, unsigned D, unsigned P,
|
||||
IdentifierInfo *Id, bool Typename);
|
||||
|
||||
/// \brief Whether this template type parameter was declared with
|
||||
/// the 'typename' keyword. If not, it was declared with the 'class'
|
||||
/// keyword.
|
||||
bool wasDeclaredWithTypename() const { return Typename; }
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const { return !DefaultArgument.isNull(); }
|
||||
|
||||
/// \brief Retrieve the default argument, if any.
|
||||
QualType getDefaultArgument() const { return DefaultArgument; }
|
||||
|
||||
/// \brief Retrieve the location of the default argument, if any.
|
||||
SourceLocation getDefaultArgumentLoc() const { return DefaultArgumentLoc; }
|
||||
|
||||
/// \brief Determines whether the default argument was inherited
|
||||
/// from a previous declaration of this template.
|
||||
bool defaultArgumentWasInherited() const { return InheritedDefault; }
|
||||
|
||||
/// \brief Set the default argument for this template parameter, and
|
||||
/// whether that default argument was inherited from another
|
||||
/// declaration.
|
||||
void setDefaultArgument(QualType DefArg, SourceLocation DefArgLoc,
|
||||
bool Inherited) {
|
||||
DefaultArgument = DefArg;
|
||||
DefaultArgumentLoc = DefArgLoc;
|
||||
InheritedDefault = Inherited;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == TemplateTypeParm;
|
||||
}
|
||||
static bool classof(const TemplateTypeParmDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// NonTypeTemplateParmDecl - Declares a non-type template parameter,
|
||||
/// e.g., "Size" in
|
||||
/// @code
|
||||
/// template<int Size> class array { };
|
||||
/// @endcode
|
||||
class NonTypeTemplateParmDecl
|
||||
: public VarDecl, protected TemplateParmPosition {
|
||||
/// \brief The default template argument, if any.
|
||||
Expr *DefaultArgument;
|
||||
|
||||
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
|
||||
unsigned P, IdentifierInfo *Id, QualType T,
|
||||
SourceLocation TSSL = SourceLocation())
|
||||
: VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL),
|
||||
TemplateParmPosition(D, P), DefaultArgument(0)
|
||||
{ }
|
||||
|
||||
public:
|
||||
static NonTypeTemplateParmDecl *
|
||||
Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
|
||||
unsigned P, IdentifierInfo *Id, QualType T,
|
||||
SourceLocation TypeSpecStartLoc = SourceLocation());
|
||||
|
||||
using TemplateParmPosition::getDepth;
|
||||
using TemplateParmPosition::getPosition;
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const { return DefaultArgument; }
|
||||
|
||||
/// \brief Retrieve the default argument, if any.
|
||||
Expr *getDefaultArgument() const { return DefaultArgument; }
|
||||
|
||||
/// \brief Retrieve the location of the default argument, if any.
|
||||
SourceLocation getDefaultArgumentLoc() const;
|
||||
|
||||
/// \brief Set the default argument for this template parameter.
|
||||
void setDefaultArgument(Expr *DefArg) {
|
||||
DefaultArgument = DefArg;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == NonTypeTemplateParm;
|
||||
}
|
||||
static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// TemplateTemplateParmDecl - Declares a template template parameter,
|
||||
/// e.g., "T" in
|
||||
/// @code
|
||||
/// template <template <typename> class T> class container { };
|
||||
/// @endcode
|
||||
/// A template template parameter is a TemplateDecl because it defines the
|
||||
/// name of a template and the template parameters allowable for substitution.
|
||||
class TemplateTemplateParmDecl
|
||||
: public TemplateDecl, protected TemplateParmPosition {
|
||||
|
||||
/// \brief The default template argument, if any.
|
||||
Expr *DefaultArgument;
|
||||
|
||||
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
|
||||
unsigned D, unsigned P,
|
||||
IdentifierInfo *Id, TemplateParameterList *Params)
|
||||
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
|
||||
TemplateParmPosition(D, P), DefaultArgument(0)
|
||||
{ }
|
||||
|
||||
public:
|
||||
static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, unsigned D,
|
||||
unsigned P, IdentifierInfo *Id,
|
||||
TemplateParameterList *Params);
|
||||
|
||||
using TemplateParmPosition::getDepth;
|
||||
using TemplateParmPosition::getPosition;
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const { return DefaultArgument; }
|
||||
|
||||
/// \brief Retrieve the default argument, if any.
|
||||
Expr *getDefaultArgument() const { return DefaultArgument; }
|
||||
|
||||
/// \brief Retrieve the location of the default argument, if any.
|
||||
SourceLocation getDefaultArgumentLoc() const;
|
||||
|
||||
/// \brief Set the default argument for this template parameter.
|
||||
void setDefaultArgument(Expr *DefArg) {
|
||||
DefaultArgument = DefArg;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == TemplateTemplateParm;
|
||||
}
|
||||
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// \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;
|
||||
};
|
||||
|
||||
/// \brief Location of the beginning of this template argument.
|
||||
SourceLocation StartLoc;
|
||||
|
||||
public:
|
||||
/// \brief The type of template argument we're storing.
|
||||
enum ArgKind {
|
||||
/// The template argument is a type. It's value is stored in the
|
||||
/// TypeOrValue field.
|
||||
Type = 0,
|
||||
/// The template argument is a declaration
|
||||
Declaration = 1,
|
||||
/// The template argument is an integral value stored in an llvm::APSInt.
|
||||
Integral = 2,
|
||||
/// The template argument is a value- or type-dependent expression
|
||||
/// stored in an Expr*.
|
||||
Expression = 3
|
||||
} Kind;
|
||||
|
||||
/// \brief Construct an empty, invalid template argument.
|
||||
TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { }
|
||||
|
||||
/// \brief Construct a template type argument.
|
||||
TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
|
||||
TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
|
||||
StartLoc = Loc;
|
||||
}
|
||||
|
||||
/// \brief Construct a template argument that refers to a
|
||||
/// declaration, which is either an external declaration or a
|
||||
/// template declaration.
|
||||
TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) {
|
||||
// FIXME: Need to be sure we have the "canonical" declaration!
|
||||
TypeOrValue = reinterpret_cast<uintptr_t>(D);
|
||||
StartLoc = Loc;
|
||||
}
|
||||
|
||||
/// \brief Construct an integral constant template argument.
|
||||
TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value,
|
||||
QualType Type)
|
||||
: Kind(Integral) {
|
||||
new (Integer.Value) llvm::APSInt(Value);
|
||||
Integer.Type = Type.getAsOpaquePtr();
|
||||
StartLoc = Loc;
|
||||
}
|
||||
|
||||
/// \brief Construct a template argument that is an expression.
|
||||
///
|
||||
/// This form of template argument only occurs in template argument
|
||||
/// lists used for dependent types and for expression; it will not
|
||||
/// occur in a non-dependent, canonical template argument list.
|
||||
TemplateArgument(Expr *E);
|
||||
|
||||
/// \brief Copy constructor for a template argument.
|
||||
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
|
||||
if (Kind == Integral) {
|
||||
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
|
||||
Integer.Type = Other.Integer.Type;
|
||||
}
|
||||
else
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
StartLoc = Other.StartLoc;
|
||||
}
|
||||
|
||||
TemplateArgument& operator=(const TemplateArgument& Other) {
|
||||
// FIXME: Does not provide the strong guarantee for exception
|
||||
// safety.
|
||||
using llvm::APSInt;
|
||||
|
||||
if (Kind == Other.Kind && Kind == Integral) {
|
||||
// Copy integral values.
|
||||
*this->getAsIntegral() = *Other.getAsIntegral();
|
||||
Integer.Type = Other.Integer.Type;
|
||||
} 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;
|
||||
}
|
||||
StartLoc = Other.StartLoc;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~TemplateArgument() {
|
||||
using llvm::APSInt;
|
||||
|
||||
if (Kind == Integral)
|
||||
getAsIntegral()->~APSInt();
|
||||
}
|
||||
|
||||
/// \brief Return the kind of stored template argument.
|
||||
ArgKind getKind() const { return Kind; }
|
||||
|
||||
/// \brief Retrieve the template argument as a type.
|
||||
QualType getAsType() const {
|
||||
if (Kind != Type)
|
||||
return QualType();
|
||||
|
||||
return QualType::getFromOpaquePtr(
|
||||
reinterpret_cast<void*>(TypeOrValue));
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as a declaration.
|
||||
Decl *getAsDecl() const {
|
||||
if (Kind != Declaration)
|
||||
return 0;
|
||||
return reinterpret_cast<Decl *>(TypeOrValue);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as an integral value.
|
||||
llvm::APSInt *getAsIntegral() {
|
||||
if (Kind != Integral)
|
||||
return 0;
|
||||
return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
|
||||
}
|
||||
|
||||
const llvm::APSInt *getAsIntegral() const {
|
||||
return const_cast<TemplateArgument*>(this)->getAsIntegral();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type of the integral value.
|
||||
QualType getIntegralType() const {
|
||||
if (Kind != Integral)
|
||||
return QualType();
|
||||
|
||||
return QualType::getFromOpaquePtr(Integer.Type);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as an expression.
|
||||
Expr *getAsExpr() const {
|
||||
if (Kind != Expression)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<Expr *>(TypeOrValue);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location where the template argument starts.
|
||||
SourceLocation getLocation() const { return StartLoc; }
|
||||
|
||||
/// \brief Used to insert TemplateArguments into FoldingSets.
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddInteger(Kind);
|
||||
switch (Kind) {
|
||||
case Type:
|
||||
getAsType().Profile(ID);
|
||||
break;
|
||||
|
||||
case Declaration:
|
||||
ID.AddPointer(getAsDecl()); // FIXME: Must be canonical!
|
||||
break;
|
||||
|
||||
case Integral:
|
||||
getAsIntegral()->Profile(ID);
|
||||
getIntegralType().Profile(ID);
|
||||
break;
|
||||
|
||||
case Expression:
|
||||
// FIXME: We need a canonical representation of expressions.
|
||||
ID.AddPointer(getAsExpr());
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// \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 not own the pointer.
|
||||
llvm::PointerIntPair<TemplateArgument *, 1> Arguments;
|
||||
|
||||
/// \brief The number of template arguments in this template
|
||||
/// argument list.
|
||||
unsigned NumArguments;
|
||||
|
||||
|
||||
public:
|
||||
TemplateArgumentList(ASTContext &Context,
|
||||
TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
bool CopyArgs);
|
||||
|
||||
~TemplateArgumentList();
|
||||
|
||||
/// \brief Retrieve the template argument at a given index.
|
||||
const TemplateArgument &get(unsigned Idx) const {
|
||||
assert(Idx < NumArguments && "Invalid template argument index");
|
||||
return getFlatArgumentList()[Idx];
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument at a given index.
|
||||
TemplateArgument &get(unsigned Idx) {
|
||||
assert(Idx < NumArguments && "Invalid template argument index");
|
||||
return getFlatArgumentList()[Idx];
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument at a given index.
|
||||
TemplateArgument &operator[](unsigned Idx) { return get(Idx); }
|
||||
const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); }
|
||||
|
||||
/// \brief Retrieve the number of template arguments in this
|
||||
/// template argument list.
|
||||
unsigned size() const { return NumArguments; }
|
||||
|
||||
/// \brief Retrieve the number of template arguments in the
|
||||
/// flattened template argument list.
|
||||
unsigned flat_size() const { return NumArguments; }
|
||||
|
||||
/// \brief Retrieve the flattened template argument list.
|
||||
TemplateArgument *getFlatArgumentList() {
|
||||
return Arguments.getPointer();
|
||||
}
|
||||
const TemplateArgument *getFlatArgumentList() const {
|
||||
return Arguments.getPointer();
|
||||
}
|
||||
};
|
||||
|
||||
// \brief Describes the kind of template specialization that a
|
||||
// particular template specialization declaration represents.
|
||||
enum TemplateSpecializationKind {
|
||||
/// This template specialization was formed from a template-id but
|
||||
/// has not yet been declared, defined, or instantiated.
|
||||
TSK_Undeclared = 0,
|
||||
/// This template specialization was declared or defined by an
|
||||
/// explicit specialization (C++ [temp.expl.spec]) or partial
|
||||
/// specialization (C++ [temp.class.spec]).
|
||||
TSK_ExplicitSpecialization,
|
||||
/// This template specialization was implicitly instantiated from a
|
||||
/// template. (C++ [temp.inst]).
|
||||
TSK_ImplicitInstantiation,
|
||||
/// This template specialization was instantiated from a template
|
||||
/// due to an explicit instantiation request (C++ [temp.explicit]).
|
||||
TSK_ExplicitInstantiation
|
||||
};
|
||||
|
||||
/// \brief Represents a class template specialization, which refers to
|
||||
/// a class template with a given set of template arguments.
|
||||
///
|
||||
/// Class template specializations represent both explicit
|
||||
/// specialization of class templates, as in the example below, and
|
||||
/// implicit instantiations of class templates.
|
||||
///
|
||||
/// \code
|
||||
/// template<typename T> class array;
|
||||
///
|
||||
/// template<>
|
||||
/// class array<bool> { }; // class template specialization array<bool>
|
||||
/// \endcode
|
||||
class ClassTemplateSpecializationDecl
|
||||
: public CXXRecordDecl, public llvm::FoldingSetNode {
|
||||
/// \brief The template that this specialization specializes
|
||||
ClassTemplateDecl *SpecializedTemplate;
|
||||
|
||||
/// \brief The template arguments used to describe this specialization.
|
||||
TemplateArgumentList TemplateArgs;
|
||||
|
||||
/// \brief The kind of specialization this declaration refers to.
|
||||
/// Really a value of type TemplateSpecializationKind.
|
||||
unsigned SpecializationKind : 2;
|
||||
|
||||
protected:
|
||||
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
|
||||
DeclContext *DC, SourceLocation L,
|
||||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs);
|
||||
|
||||
public:
|
||||
static ClassTemplateSpecializationDecl *
|
||||
Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
|
||||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
|
||||
ClassTemplateSpecializationDecl *PrevDecl);
|
||||
|
||||
/// \brief Retrieve the template that this specialization specializes.
|
||||
ClassTemplateDecl *getSpecializedTemplate() const {
|
||||
return SpecializedTemplate;
|
||||
}
|
||||
|
||||
const TemplateArgumentList &getTemplateArgs() const {
|
||||
return TemplateArgs;
|
||||
}
|
||||
|
||||
/// \brief Determine the kind of specialization that this
|
||||
/// declaration represents.
|
||||
TemplateSpecializationKind getSpecializationKind() const {
|
||||
return static_cast<TemplateSpecializationKind>(SpecializationKind);
|
||||
}
|
||||
|
||||
void setSpecializationKind(TemplateSpecializationKind TSK) {
|
||||
SpecializationKind = TSK;
|
||||
}
|
||||
|
||||
/// \brief Sets the type of this specialization as it was written by
|
||||
/// the user. This will be a class template specialization type.
|
||||
void setTypeAsWritten(QualType T) {
|
||||
TypeForDecl = T.getTypePtr();
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size());
|
||||
}
|
||||
|
||||
static void
|
||||
Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs) {
|
||||
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
|
||||
TemplateArgs[Arg].Profile(ID);
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == ClassTemplateSpecialization ||
|
||||
D->getKind() == ClassTemplatePartialSpecialization;
|
||||
}
|
||||
|
||||
static bool classof(const ClassTemplateSpecializationDecl *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ClassTemplatePartialSpecializationDecl
|
||||
: public ClassTemplateSpecializationDecl
|
||||
{
|
||||
/// \brief The list of template parameters
|
||||
TemplateParameterList* TemplateParams;
|
||||
|
||||
ClassTemplatePartialSpecializationDecl(ASTContext &Context,
|
||||
DeclContext *DC, SourceLocation L,
|
||||
TemplateParameterList *Params,
|
||||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs)
|
||||
: ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization,
|
||||
DC, L, SpecializedTemplate, TemplateArgs,
|
||||
NumTemplateArgs),
|
||||
TemplateParams(Params) { }
|
||||
|
||||
public:
|
||||
static ClassTemplatePartialSpecializationDecl *
|
||||
Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
|
||||
TemplateParameterList *Params,
|
||||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl);
|
||||
|
||||
/// Get the list of template parameters
|
||||
TemplateParameterList *getTemplateParameters() const {
|
||||
return TemplateParams;
|
||||
}
|
||||
|
||||
// FIXME: Add Profile support!
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == ClassTemplatePartialSpecialization;
|
||||
}
|
||||
|
||||
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/// Declaration of a class template.
|
||||
class ClassTemplateDecl : public TemplateDecl {
|
||||
protected:
|
||||
/// \brief Data that is common to all of the declarations of a given
|
||||
/// class template.
|
||||
struct Common {
|
||||
/// \brief The class template specializations for this class
|
||||
/// template, including explicit specializations and instantiations.
|
||||
llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
|
||||
|
||||
/// \brief The class template partial specializations for this class
|
||||
/// template.
|
||||
llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>
|
||||
PartialSpecializations;
|
||||
|
||||
/// \brief The injected-class-name type for this class template.
|
||||
QualType InjectedClassNameType;
|
||||
};
|
||||
|
||||
/// \brief Previous declaration of this class template.
|
||||
ClassTemplateDecl *PreviousDeclaration;
|
||||
|
||||
/// \brief Pointer to the data that is common to all of the
|
||||
/// declarations of this class template.
|
||||
///
|
||||
/// The first declaration of a class template (e.g., the declaration
|
||||
/// with no "previous declaration") owns this pointer.
|
||||
Common *CommonPtr;
|
||||
|
||||
ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl,
|
||||
ClassTemplateDecl *PrevDecl, Common *CommonPtr)
|
||||
: TemplateDecl(ClassTemplate, DC, L, Name, Params, Decl),
|
||||
PreviousDeclaration(PrevDecl), CommonPtr(CommonPtr) { }
|
||||
|
||||
~ClassTemplateDecl();
|
||||
|
||||
public:
|
||||
/// Get the underlying class declarations of the template.
|
||||
CXXRecordDecl *getTemplatedDecl() const {
|
||||
return static_cast<CXXRecordDecl *>(TemplatedDecl);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the previous declaration of this template.
|
||||
ClassTemplateDecl *getPreviousDeclaration() const {
|
||||
return PreviousDeclaration;
|
||||
}
|
||||
|
||||
/// Create a class template node.
|
||||
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,
|
||||
DeclarationName Name,
|
||||
TemplateParameterList *Params,
|
||||
NamedDecl *Decl,
|
||||
ClassTemplateDecl *PrevDecl);
|
||||
|
||||
/// \brief Retrieve the set of specializations of this class template.
|
||||
llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations() {
|
||||
return CommonPtr->Specializations;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the set of partial specializations of this class
|
||||
/// template.
|
||||
llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &
|
||||
getPartialSpecializations() {
|
||||
return CommonPtr->PartialSpecializations;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type of the injected-class-name for this
|
||||
/// class template.
|
||||
///
|
||||
/// The injected-class-name for a class template \c X is \c
|
||||
/// X<template-args>, where \c template-args is formed from the
|
||||
/// template arguments that correspond to the template parameters of
|
||||
/// \c X. For example:
|
||||
///
|
||||
/// \code
|
||||
/// template<typename T, int N>
|
||||
/// struct array {
|
||||
/// typedef array this_type; // "array" is equivalent to "array<T, N>"
|
||||
/// };
|
||||
/// \endcode
|
||||
QualType getInjectedClassNameType(ASTContext &Context);
|
||||
|
||||
// Implement isa/cast/dyncast support
|
||||
static bool classof(const Decl *D)
|
||||
{ return D->getKind() == ClassTemplate; }
|
||||
static bool classof(const ClassTemplateDecl *D)
|
||||
{ return true; }
|
||||
|
||||
virtual void Destroy(ASTContext& C);
|
||||
};
|
||||
|
||||
} /* end of namespace clang */
|
||||
|
||||
#endif
|
54
include/clang/AST/DeclVisitor.h
Normal file
54
include/clang/AST/DeclVisitor.h
Normal file
@ -0,0 +1,54 @@
|
||||
//===--- DeclVisitor.h - Visitor for Decl subclasses ------------*- 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 DeclVisitor interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_DECLVISITOR_H
|
||||
#define LLVM_CLANG_AST_DECLVISITOR_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
#define DISPATCH(NAME, CLASS) \
|
||||
return static_cast<ImplClass*>(this)-> Visit##NAME(static_cast<CLASS*>(D))
|
||||
|
||||
/// \brief A simple visitor class that helps create declaration visitors.
|
||||
template<typename ImplClass, typename RetTy=void>
|
||||
class DeclVisitor {
|
||||
public:
|
||||
RetTy Visit(Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
default: assert(false && "Decl that isn't part of DeclNodes.def!");
|
||||
#define DECL(Derived, Base) \
|
||||
case Decl::Derived: DISPATCH(Derived##Decl, Derived##Decl);
|
||||
#define ABSTRACT_DECL(Derived, Base)
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
}
|
||||
}
|
||||
|
||||
// If the implementation chooses not to implement a certain visit
|
||||
// method, fall back to the parent.
|
||||
#define DECL(Derived, Base) \
|
||||
RetTy Visit##Derived##Decl(Derived##Decl *D) { DISPATCH(Base, Base); }
|
||||
#define ABSTRACT_DECL(Derived, Base) DECL(Derived, Base)
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
|
||||
RetTy VisitDecl(Decl *D) { return RetTy(); }
|
||||
};
|
||||
|
||||
#undef DISPATCH
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_DECLVISITOR_H
|
357
include/clang/AST/DeclarationName.h
Normal file
357
include/clang/AST/DeclarationName.h
Normal file
@ -0,0 +1,357 @@
|
||||
//===-- DeclarationName.h - Representation of declaration names -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the DeclarationName and DeclarationNameTable classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_DECLARATIONNAME_H
|
||||
#define LLVM_CLANG_AST_DECLARATIONNAME_H
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace llvm {
|
||||
template <typename T> struct DenseMapInfo;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class CXXSpecialName;
|
||||
class CXXOperatorIdName;
|
||||
class DeclarationNameExtra;
|
||||
class IdentifierInfo;
|
||||
class MultiKeywordSelector;
|
||||
class UsingDirectiveDecl;
|
||||
|
||||
/// DeclarationName - The name of a declaration. In the common case,
|
||||
/// this just stores an IdentifierInfo pointer to a normal
|
||||
/// name. However, it also provides encodings for Objective-C
|
||||
/// selectors (optimizing zero- and one-argument selectors, which make
|
||||
/// up 78% percent of all selectors in Cocoa.h) and special C++ names
|
||||
/// for constructors, destructors, and conversion functions.
|
||||
class DeclarationName {
|
||||
public:
|
||||
/// NameKind - The kind of name this object contains.
|
||||
enum NameKind {
|
||||
Identifier,
|
||||
ObjCZeroArgSelector,
|
||||
ObjCOneArgSelector,
|
||||
ObjCMultiArgSelector,
|
||||
CXXConstructorName,
|
||||
CXXDestructorName,
|
||||
CXXConversionFunctionName,
|
||||
CXXOperatorName,
|
||||
CXXUsingDirective
|
||||
};
|
||||
|
||||
private:
|
||||
/// StoredNameKind - The kind of name that is actually stored in the
|
||||
/// upper bits of the Ptr field. This is only used internally.
|
||||
enum StoredNameKind {
|
||||
StoredIdentifier = 0,
|
||||
StoredObjCZeroArgSelector,
|
||||
StoredObjCOneArgSelector,
|
||||
StoredDeclarationNameExtra,
|
||||
PtrMask = 0x03
|
||||
};
|
||||
|
||||
/// Ptr - The lowest two bits are used to express what kind of name
|
||||
/// we're actually storing, using the values of NameKind. Depending
|
||||
/// on the kind of name this is, the upper bits of Ptr may have one
|
||||
/// of several different meanings:
|
||||
///
|
||||
/// StoredIdentifier - The name is a normal identifier, and Ptr is
|
||||
/// a normal IdentifierInfo pointer.
|
||||
///
|
||||
/// StoredObjCZeroArgSelector - The name is an Objective-C
|
||||
/// selector with zero arguments, and Ptr is an IdentifierInfo
|
||||
/// pointer pointing to the selector name.
|
||||
///
|
||||
/// StoredObjCOneArgSelector - The name is an Objective-C selector
|
||||
/// with one argument, and Ptr is an IdentifierInfo pointer
|
||||
/// pointing to the selector name.
|
||||
///
|
||||
/// StoredDeclarationNameExtra - Ptr is actually a pointer to a
|
||||
/// DeclarationNameExtra structure, whose first value will tell us
|
||||
/// whether this is an Objective-C selector, C++ operator-id name,
|
||||
/// or special C++ name.
|
||||
uintptr_t Ptr;
|
||||
|
||||
/// getStoredNameKind - Return the kind of object that is stored in
|
||||
/// Ptr.
|
||||
StoredNameKind getStoredNameKind() const {
|
||||
return static_cast<StoredNameKind>(Ptr & PtrMask);
|
||||
}
|
||||
|
||||
/// getExtra - Get the "extra" information associated with this
|
||||
/// multi-argument selector or C++ special name.
|
||||
DeclarationNameExtra *getExtra() const {
|
||||
assert(getStoredNameKind() == StoredDeclarationNameExtra &&
|
||||
"Declaration name does not store an Extra structure");
|
||||
return reinterpret_cast<DeclarationNameExtra *>(Ptr & ~PtrMask);
|
||||
}
|
||||
|
||||
/// getAsCXXSpecialName - If the stored pointer is actually a
|
||||
/// CXXSpecialName, returns a pointer to it. Otherwise, returns
|
||||
/// a NULL pointer.
|
||||
CXXSpecialName *getAsCXXSpecialName() const {
|
||||
if (getNameKind() >= CXXConstructorName &&
|
||||
getNameKind() <= CXXConversionFunctionName)
|
||||
return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// getAsCXXOperatorIdName
|
||||
CXXOperatorIdName *getAsCXXOperatorIdName() const {
|
||||
if (getNameKind() == CXXOperatorName)
|
||||
return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Construct a declaration name from the name of a C++ constructor,
|
||||
// destructor, or conversion function.
|
||||
DeclarationName(CXXSpecialName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
||||
// Construct a declaration name from the name of a C++ overloaded
|
||||
// operator.
|
||||
DeclarationName(CXXOperatorIdName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
||||
/// Construct a declaration name from a raw pointer.
|
||||
DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { }
|
||||
|
||||
friend class DeclarationNameTable;
|
||||
friend class NamedDecl;
|
||||
|
||||
/// getFETokenInfoAsVoid - Retrieves the front end-specified pointer
|
||||
/// for this name as a void pointer.
|
||||
void *getFETokenInfoAsVoid() const;
|
||||
|
||||
public:
|
||||
/// DeclarationName - Used to create an empty selector.
|
||||
DeclarationName() : Ptr(0) { }
|
||||
|
||||
// Construct a declaration name from an IdentifierInfo *.
|
||||
DeclarationName(const IdentifierInfo *II)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(II)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
|
||||
}
|
||||
|
||||
// Construct a declaration name from an Objective-C selector.
|
||||
DeclarationName(Selector Sel);
|
||||
|
||||
/// getUsingDirectiveName - Return name for all using-directives.
|
||||
static DeclarationName getUsingDirectiveName();
|
||||
|
||||
// operator bool() - Evaluates true when this declaration name is
|
||||
// non-empty.
|
||||
operator bool() const {
|
||||
return ((Ptr & PtrMask) != 0) ||
|
||||
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
|
||||
}
|
||||
|
||||
/// Predicate functions for querying what type of name this is.
|
||||
bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; }
|
||||
bool isObjCZeroArgSelector() const {
|
||||
return getStoredNameKind() == StoredObjCZeroArgSelector;
|
||||
}
|
||||
bool isObjCOneArgSelector() const {
|
||||
return getStoredNameKind() == StoredObjCOneArgSelector;
|
||||
}
|
||||
|
||||
/// getNameKind - Determine what kind of name this is.
|
||||
NameKind getNameKind() const;
|
||||
|
||||
|
||||
/// getName - Retrieve the human-readable string for this name.
|
||||
std::string getAsString() const;
|
||||
|
||||
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
|
||||
/// this declaration name, or NULL if this declaration name isn't a
|
||||
/// simple identifier.
|
||||
IdentifierInfo *getAsIdentifierInfo() const {
|
||||
if (isIdentifier())
|
||||
return reinterpret_cast<IdentifierInfo *>(Ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// getAsOpaqueInteger - Get the representation of this declaration
|
||||
/// name as an opaque integer.
|
||||
uintptr_t getAsOpaqueInteger() const { return Ptr; }
|
||||
|
||||
/// getAsOpaquePtr - Get the representation of this declaration name as
|
||||
/// an opaque pointer.
|
||||
void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); }
|
||||
|
||||
static DeclarationName getFromOpaqueInteger(uintptr_t P) {
|
||||
DeclarationName N;
|
||||
N.Ptr = P;
|
||||
return N;
|
||||
}
|
||||
|
||||
/// getCXXNameType - If this name is one of the C++ names (of a
|
||||
/// constructor, destructor, or conversion function), return the
|
||||
/// type associated with that name.
|
||||
QualType getCXXNameType() const;
|
||||
|
||||
/// getCXXOverloadedOperator - If this name is the name of an
|
||||
/// overloadable operator in C++ (e.g., @c operator+), retrieve the
|
||||
/// kind of overloaded operator.
|
||||
OverloadedOperatorKind getCXXOverloadedOperator() const;
|
||||
|
||||
/// getObjCSelector - Get the Objective-C selector stored in this
|
||||
/// declaration name.
|
||||
Selector getObjCSelector() const;
|
||||
|
||||
/// getFETokenInfo/setFETokenInfo - The language front-end is
|
||||
/// allowed to associate arbitrary metadata with some kinds of
|
||||
/// declaration names, including normal identifiers and C++
|
||||
/// constructors, destructors, and conversion functions.
|
||||
template<typename T>
|
||||
T *getFETokenInfo() const { return static_cast<T*>(getFETokenInfoAsVoid()); }
|
||||
|
||||
void setFETokenInfo(void *T);
|
||||
|
||||
/// operator== - Determine whether the specified names are identical..
|
||||
friend bool operator==(DeclarationName LHS, DeclarationName RHS) {
|
||||
return LHS.Ptr == RHS.Ptr;
|
||||
}
|
||||
|
||||
/// operator!= - Determine whether the specified names are different.
|
||||
friend bool operator!=(DeclarationName LHS, DeclarationName RHS) {
|
||||
return LHS.Ptr != RHS.Ptr;
|
||||
}
|
||||
|
||||
static DeclarationName getEmptyMarker() {
|
||||
return DeclarationName(uintptr_t(-1));
|
||||
}
|
||||
|
||||
static DeclarationName getTombstoneMarker() {
|
||||
return DeclarationName(uintptr_t(-2));
|
||||
}
|
||||
};
|
||||
|
||||
/// Ordering on two declaration names. If both names are identifiers,
|
||||
/// this provides a lexicographical ordering.
|
||||
bool operator<(DeclarationName LHS, DeclarationName RHS);
|
||||
|
||||
/// Ordering on two declaration names. If both names are identifiers,
|
||||
/// this provides a lexicographical ordering.
|
||||
inline bool operator>(DeclarationName LHS, DeclarationName RHS) {
|
||||
return RHS < LHS;
|
||||
}
|
||||
|
||||
/// Ordering on two declaration names. If both names are identifiers,
|
||||
/// this provides a lexicographical ordering.
|
||||
inline bool operator<=(DeclarationName LHS, DeclarationName RHS) {
|
||||
return !(RHS < LHS);
|
||||
}
|
||||
|
||||
/// Ordering on two declaration names. If both names are identifiers,
|
||||
/// this provides a lexicographical ordering.
|
||||
inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
|
||||
return !(LHS < RHS);
|
||||
}
|
||||
|
||||
/// DeclarationNameTable - Used to store and retrieve DeclarationName
|
||||
/// instances for the various kinds of declaration names, e.g., normal
|
||||
/// identifiers, C++ constructor names, etc. This class contains
|
||||
/// uniqued versions of each of the C++ special names, which can be
|
||||
/// retrieved using its member functions (e.g.,
|
||||
/// getCXXConstructorName).
|
||||
class DeclarationNameTable {
|
||||
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
|
||||
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
||||
|
||||
DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
|
||||
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
|
||||
|
||||
public:
|
||||
DeclarationNameTable();
|
||||
~DeclarationNameTable();
|
||||
|
||||
/// getIdentifier - Create a declaration name that is a simple
|
||||
/// identifier.
|
||||
DeclarationName getIdentifier(IdentifierInfo *ID) {
|
||||
return DeclarationName(ID);
|
||||
}
|
||||
|
||||
/// getCXXConstructorName - Returns the name of a C++ constructor
|
||||
/// for the given Type.
|
||||
DeclarationName getCXXConstructorName(QualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXDestructorName - Returns the name of a C++ destructor
|
||||
/// for the given Type.
|
||||
DeclarationName getCXXDestructorName(QualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXConversionFunctionName - Returns the name of a C++
|
||||
/// conversion function for the given Type.
|
||||
DeclarationName getCXXConversionFunctionName(QualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXSpecialName - Returns a declaration name for special kind
|
||||
/// of C++ name, e.g., for a constructor, destructor, or conversion
|
||||
/// function.
|
||||
DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind,
|
||||
QualType Ty);
|
||||
|
||||
/// getCXXOperatorName - Get the name of the overloadable C++
|
||||
/// operator corresponding to Op.
|
||||
DeclarationName getCXXOperatorName(OverloadedOperatorKind Op);
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending DeclarationName's
|
||||
/// into a diagnostic with <<.
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
DeclarationName N) {
|
||||
DB.AddTaggedVal(N.getAsOpaqueInteger(),
|
||||
Diagnostic::ak_declarationname);
|
||||
return DB;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
/// Define DenseMapInfo so that DeclarationNames can be used as keys
|
||||
/// in DenseMap and DenseSets.
|
||||
template<>
|
||||
struct DenseMapInfo<clang::DeclarationName> {
|
||||
static inline clang::DeclarationName getEmptyKey() {
|
||||
return clang::DeclarationName::getEmptyMarker();
|
||||
}
|
||||
|
||||
static inline clang::DeclarationName getTombstoneKey() {
|
||||
return clang::DeclarationName::getTombstoneMarker();
|
||||
}
|
||||
|
||||
static unsigned getHashValue(clang::DeclarationName);
|
||||
|
||||
static inline bool
|
||||
isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
|
||||
static inline bool isPod() { return true; }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
2500
include/clang/AST/Expr.h
Normal file
2500
include/clang/AST/Expr.h
Normal file
File diff suppressed because it is too large
Load Diff
1234
include/clang/AST/ExprCXX.h
Normal file
1234
include/clang/AST/ExprCXX.h
Normal file
File diff suppressed because it is too large
Load Diff
494
include/clang/AST/ExprObjC.h
Normal file
494
include/clang/AST/ExprObjC.h
Normal file
@ -0,0 +1,494 @@
|
||||
//===--- ExprObjC.h - Classes for representing ObjC expressions -*- 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 ExprObjC interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_EXPROBJC_H
|
||||
#define LLVM_CLANG_AST_EXPROBJC_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".
|
||||
class ObjCStringLiteral : public Expr {
|
||||
Stmt *String;
|
||||
SourceLocation AtLoc;
|
||||
public:
|
||||
ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L)
|
||||
: Expr(ObjCStringLiteralClass, T), String(SL), AtLoc(L) {}
|
||||
explicit ObjCStringLiteral(EmptyShell Empty)
|
||||
: Expr(ObjCStringLiteralClass, Empty) {}
|
||||
|
||||
StringLiteral *getString() { return cast<StringLiteral>(String); }
|
||||
const StringLiteral *getString() const { return cast<StringLiteral>(String); }
|
||||
void setString(StringLiteral *S) { String = S; }
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, String->getLocEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCStringLiteralClass;
|
||||
}
|
||||
static bool classof(const ObjCStringLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type
|
||||
/// and behavior as StringLiteral except that the string initializer is obtained
|
||||
/// from ASTContext with the encoding type as an argument.
|
||||
class ObjCEncodeExpr : public Expr {
|
||||
QualType EncType;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
public:
|
||||
ObjCEncodeExpr(QualType T, QualType ET,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCEncodeExprClass, T), EncType(ET), AtLoc(at), RParenLoc(rp) {}
|
||||
|
||||
explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){}
|
||||
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
QualType getEncodedType() const { return EncType; }
|
||||
void setEncodedType(QualType T) { EncType = T; }
|
||||
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCEncodeExprClass;
|
||||
}
|
||||
static bool classof(const ObjCEncodeExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCSelectorExpr used for @selector in Objective-C.
|
||||
class ObjCSelectorExpr : public Expr {
|
||||
Selector SelName;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
public:
|
||||
ObjCSelectorExpr(QualType T, Selector selInfo,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCSelectorExprClass, T), SelName(selInfo), AtLoc(at), RParenLoc(rp){}
|
||||
explicit ObjCSelectorExpr(EmptyShell Empty)
|
||||
: Expr(ObjCSelectorExprClass, Empty) {}
|
||||
|
||||
Selector getSelector() const { return SelName; }
|
||||
void setSelector(Selector S) { SelName = S; }
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
/// getNumArgs - Return the number of actual arguments to this call.
|
||||
unsigned getNumArgs() const { return SelName.getNumArgs(); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCSelectorExprClass;
|
||||
}
|
||||
static bool classof(const ObjCSelectorExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCProtocolExpr used for protocol expression in Objective-C. This is used
|
||||
/// as: @protocol(foo), as in:
|
||||
/// obj conformsToProtocol:@protocol(foo)]
|
||||
/// The return type is "Protocol*".
|
||||
class ObjCProtocolExpr : public Expr {
|
||||
ObjCProtocolDecl *Protocol;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
public:
|
||||
ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCProtocolExprClass, T), Protocol(protocol),
|
||||
AtLoc(at), RParenLoc(rp) {}
|
||||
explicit ObjCProtocolExpr(EmptyShell Empty)
|
||||
: Expr(ObjCProtocolExprClass, Empty) {}
|
||||
|
||||
ObjCProtocolDecl *getProtocol() const { return Protocol; }
|
||||
void setProtocol(ObjCProtocolDecl *P) { Protocol = P; }
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCProtocolExprClass;
|
||||
}
|
||||
static bool classof(const ObjCProtocolExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCIvarRefExpr - A reference to an ObjC instance variable.
|
||||
class ObjCIvarRefExpr : public Expr {
|
||||
class ObjCIvarDecl *D;
|
||||
SourceLocation Loc;
|
||||
Stmt *Base;
|
||||
bool IsArrow:1; // True if this is "X->F", false if this is "X.F".
|
||||
bool IsFreeIvar:1; // True if ivar reference has no base (self assumed).
|
||||
|
||||
public:
|
||||
ObjCIvarRefExpr(ObjCIvarDecl *d,
|
||||
QualType t, SourceLocation l, Expr *base=0,
|
||||
bool arrow = false, bool freeIvar = false) :
|
||||
Expr(ObjCIvarRefExprClass, t), D(d),
|
||||
Loc(l), Base(base), IsArrow(arrow),
|
||||
IsFreeIvar(freeIvar) {}
|
||||
|
||||
explicit ObjCIvarRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCIvarRefExprClass, Empty) {}
|
||||
|
||||
ObjCIvarDecl *getDecl() { return D; }
|
||||
const ObjCIvarDecl *getDecl() const { return D; }
|
||||
void setDecl(ObjCIvarDecl *d) { D = d; }
|
||||
|
||||
const Expr *getBase() const { return cast<Expr>(Base); }
|
||||
Expr *getBase() { return cast<Expr>(Base); }
|
||||
void setBase(Expr * base) { Base = base; }
|
||||
|
||||
bool isArrow() const { return IsArrow; }
|
||||
bool isFreeIvar() const { return IsFreeIvar; }
|
||||
void setIsArrow(bool A) { IsArrow = A; }
|
||||
void setIsFreeIvar(bool A) { IsFreeIvar = A; }
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return isFreeIvar() ? SourceRange(Loc)
|
||||
: SourceRange(getBase()->getLocStart(), Loc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCIvarRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCIvarRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
|
||||
/// property.
|
||||
///
|
||||
class ObjCPropertyRefExpr : public Expr {
|
||||
private:
|
||||
ObjCPropertyDecl *AsProperty;
|
||||
SourceLocation IdLoc;
|
||||
Stmt *Base;
|
||||
public:
|
||||
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCPropertyRefExprClass, t), AsProperty(PD), IdLoc(l), Base(base) {
|
||||
}
|
||||
|
||||
explicit ObjCPropertyRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCPropertyRefExprClass, Empty) {}
|
||||
|
||||
ObjCPropertyDecl *getProperty() const { return AsProperty; }
|
||||
void setProperty(ObjCPropertyDecl *D) { AsProperty = D; }
|
||||
|
||||
const Expr *getBase() const { return cast<Expr>(Base); }
|
||||
Expr *getBase() { return cast<Expr>(Base); }
|
||||
void setBase(Expr *base) { Base = base; }
|
||||
|
||||
SourceLocation getLocation() const { return IdLoc; }
|
||||
void setLocation(SourceLocation L) { IdLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), IdLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCPropertyRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCPropertyRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCKVCRefExpr - A dot-syntax expression to access "implicit" properties
|
||||
/// (i.e. methods following the property naming convention). KVC stands for
|
||||
/// Key Value Encoding, a generic concept for accessing or setting a 'Key'
|
||||
/// value for an object.
|
||||
///
|
||||
class ObjCKVCRefExpr : public Expr {
|
||||
ObjCMethodDecl *Setter;
|
||||
ObjCMethodDecl *Getter;
|
||||
SourceLocation Loc;
|
||||
// FIXME: Swizzle these into a single pointer.
|
||||
Stmt *Base;
|
||||
ObjCInterfaceDecl *ClassProp;
|
||||
SourceLocation ClassLoc;
|
||||
|
||||
public:
|
||||
ObjCKVCRefExpr(ObjCMethodDecl *getter,
|
||||
QualType t,
|
||||
ObjCMethodDecl *setter,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCKVCRefExprClass, t), Setter(setter),
|
||||
Getter(getter), Loc(l), Base(base), ClassProp(0),
|
||||
ClassLoc(SourceLocation()) {
|
||||
}
|
||||
ObjCKVCRefExpr(ObjCMethodDecl *getter,
|
||||
QualType t,
|
||||
ObjCMethodDecl *setter,
|
||||
SourceLocation l, ObjCInterfaceDecl *C, SourceLocation CL)
|
||||
: Expr(ObjCKVCRefExprClass, t), Setter(setter),
|
||||
Getter(getter), Loc(l), Base(0), ClassProp(C), ClassLoc(CL) {
|
||||
}
|
||||
explicit ObjCKVCRefExpr(EmptyShell Empty) : Expr(ObjCKVCRefExprClass, Empty){}
|
||||
|
||||
ObjCMethodDecl *getGetterMethod() const { return Getter; }
|
||||
ObjCMethodDecl *getSetterMethod() const { return Setter; }
|
||||
ObjCInterfaceDecl *getClassProp() const { return ClassProp; }
|
||||
void setGetterMethod(ObjCMethodDecl *D) { Getter = D; }
|
||||
void setSetterMethod(ObjCMethodDecl *D) { Setter = D; }
|
||||
void setClassProp(ObjCInterfaceDecl *D) { ClassProp = D; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
if (Base)
|
||||
return SourceRange(getBase()->getLocStart(), Loc);
|
||||
return SourceRange(ClassLoc, Loc);
|
||||
}
|
||||
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 Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
SourceLocation getClassLoc() const { return ClassLoc; }
|
||||
void setClassLoc(SourceLocation L) { ClassLoc = L; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCKVCRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCKVCRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
class ObjCMessageExpr : public Expr {
|
||||
// SubExprs - The receiver and arguments of the message expression.
|
||||
Stmt **SubExprs;
|
||||
|
||||
// NumArgs - The number of arguments (not including the receiver) to the
|
||||
// message expression.
|
||||
unsigned NumArgs;
|
||||
|
||||
// A unigue name for this message.
|
||||
Selector SelName;
|
||||
|
||||
// A method prototype for this message (optional).
|
||||
// FIXME: Since method decls contain the selector, and most messages have a
|
||||
// prototype, consider devising a scheme for unifying SelName/MethodProto.
|
||||
ObjCMethodDecl *MethodProto;
|
||||
|
||||
SourceLocation LBracloc, RBracloc;
|
||||
|
||||
// Constants for indexing into SubExprs.
|
||||
enum { RECEIVER=0, ARGS_START=1 };
|
||||
|
||||
// Bit-swizzling flags.
|
||||
enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 };
|
||||
unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; }
|
||||
|
||||
public:
|
||||
/// This constructor is used to represent class messages where the
|
||||
/// ObjCInterfaceDecl* of the receiver is not known.
|
||||
ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
|
||||
QualType retType, ObjCMethodDecl *methDecl,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
Expr **ArgExprs, unsigned NumArgs);
|
||||
|
||||
/// This constructor is used to represent class messages where the
|
||||
/// ObjCInterfaceDecl* of the receiver is known.
|
||||
// FIXME: clsName should be typed to ObjCInterfaceType
|
||||
ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo,
|
||||
QualType retType, ObjCMethodDecl *methDecl,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
Expr **ArgExprs, unsigned NumArgs);
|
||||
|
||||
// constructor for instance messages.
|
||||
ObjCMessageExpr(Expr *receiver, Selector selInfo,
|
||||
QualType retType, ObjCMethodDecl *methDecl,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
Expr **ArgExprs, unsigned NumArgs);
|
||||
|
||||
explicit ObjCMessageExpr(EmptyShell Empty)
|
||||
: Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {}
|
||||
|
||||
~ObjCMessageExpr() {
|
||||
delete [] SubExprs;
|
||||
}
|
||||
|
||||
/// getReceiver - Returns the receiver of the message expression.
|
||||
/// This can be NULL if the message is for class methods. For
|
||||
/// class methods, use getClassName.
|
||||
/// FIXME: need to handle/detect 'super' usage within a class method.
|
||||
Expr *getReceiver() {
|
||||
uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
|
||||
return (x & Flags) == IsInstMeth ? (Expr*) x : 0;
|
||||
}
|
||||
const Expr *getReceiver() const {
|
||||
return const_cast<ObjCMessageExpr*>(this)->getReceiver();
|
||||
}
|
||||
// FIXME: need setters for different receiver types.
|
||||
void setReceiver(Expr *rec) { SubExprs[RECEIVER] = rec; }
|
||||
Selector getSelector() const { return SelName; }
|
||||
void setSelector(Selector S) { SelName = S; }
|
||||
|
||||
const ObjCMethodDecl *getMethodDecl() const { return MethodProto; }
|
||||
ObjCMethodDecl *getMethodDecl() { return MethodProto; }
|
||||
void setMethodDecl(ObjCMethodDecl *MD) { MethodProto = MD; }
|
||||
|
||||
typedef std::pair<ObjCInterfaceDecl*, IdentifierInfo*> ClassInfo;
|
||||
|
||||
/// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl*
|
||||
/// and IdentifierInfo* of the invoked class. Both can be NULL if this
|
||||
/// is an instance message, and the ObjCInterfaceDecl* can be NULL if none
|
||||
/// was available when this ObjCMessageExpr object was constructed.
|
||||
ClassInfo getClassInfo() const;
|
||||
void setClassInfo(const ClassInfo &C);
|
||||
|
||||
/// getClassName - For class methods, this returns the invoked class,
|
||||
/// and returns NULL otherwise. For instance methods, use getReceiver.
|
||||
IdentifierInfo *getClassName() const {
|
||||
return getClassInfo().second;
|
||||
}
|
||||
|
||||
/// getNumArgs - Return the number of actual arguments to this call.
|
||||
unsigned getNumArgs() const { return NumArgs; }
|
||||
void setNumArgs(unsigned nArgs) {
|
||||
NumArgs = nArgs;
|
||||
// FIXME: should always allocate SubExprs via the ASTContext's
|
||||
// allocator.
|
||||
if (!SubExprs)
|
||||
SubExprs = new Stmt* [NumArgs + 1];
|
||||
}
|
||||
|
||||
/// getArg - Return the specified argument.
|
||||
Expr *getArg(unsigned Arg) {
|
||||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
return cast<Expr>(SubExprs[Arg+ARGS_START]);
|
||||
}
|
||||
const Expr *getArg(unsigned Arg) const {
|
||||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
return cast<Expr>(SubExprs[Arg+ARGS_START]);
|
||||
}
|
||||
/// setArg - Set the specified argument.
|
||||
void setArg(unsigned Arg, Expr *ArgExpr) {
|
||||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
SubExprs[Arg+ARGS_START] = ArgExpr;
|
||||
}
|
||||
|
||||
SourceLocation getLeftLoc() const { return LBracloc; }
|
||||
SourceLocation getRightLoc() const { return RBracloc; }
|
||||
|
||||
void setLeftLoc(SourceLocation L) { LBracloc = L; }
|
||||
void setRightLoc(SourceLocation L) { RBracloc = L; }
|
||||
|
||||
void setSourceRange(SourceRange R) {
|
||||
LBracloc = R.getBegin();
|
||||
RBracloc = R.getEnd();
|
||||
}
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(LBracloc, RBracloc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCMessageExprClass;
|
||||
}
|
||||
static bool classof(const ObjCMessageExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
typedef ExprIterator arg_iterator;
|
||||
typedef ConstExprIterator const_arg_iterator;
|
||||
|
||||
arg_iterator arg_begin() { return &SubExprs[ARGS_START]; }
|
||||
arg_iterator arg_end() { return &SubExprs[ARGS_START] + NumArgs; }
|
||||
const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; }
|
||||
const_arg_iterator arg_end() const { return &SubExprs[ARGS_START] + NumArgs; }
|
||||
};
|
||||
|
||||
/// ObjCSuperExpr - Represents the "super" expression in Objective-C,
|
||||
/// which refers to the object on which the current method is executing.
|
||||
class ObjCSuperExpr : public Expr {
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
ObjCSuperExpr(SourceLocation L, QualType Type)
|
||||
: Expr(ObjCSuperExprClass, Type), 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;
|
||||
}
|
||||
static bool classof(const ObjCSuperExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
184
include/clang/AST/ExternalASTSource.h
Normal file
184
include/clang/AST/ExternalASTSource.h
Normal file
@ -0,0 +1,184 @@
|
||||
//===--- ExternalASTSource.h - Abstract External AST 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 ExternalASTSource interface, which enables
|
||||
// construction of AST nodes from some external source.x
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
||||
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
||||
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <cassert>
|
||||
namespace clang {
|
||||
|
||||
class ASTConsumer;
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class ExternalSemaSource; // layering violation required for downcasting
|
||||
class Stmt;
|
||||
|
||||
/// \brief The deserialized representation of a set of declarations
|
||||
/// with the same name that are visible in a given context.
|
||||
struct VisibleDeclaration {
|
||||
/// \brief The name of the declarations.
|
||||
DeclarationName Name;
|
||||
|
||||
/// \brief The ID numbers of all of the declarations with this name.
|
||||
///
|
||||
/// These declarations have not necessarily been de-serialized.
|
||||
llvm::SmallVector<unsigned, 4> Declarations;
|
||||
};
|
||||
|
||||
/// \brief Abstract interface for external sources of AST nodes.
|
||||
///
|
||||
/// External AST sources provide AST nodes constructed from some
|
||||
/// external source, such as a precompiled header. External AST
|
||||
/// sources can resolve types and declarations from abstract IDs into
|
||||
/// actual type and declaration nodes, and read parts of declaration
|
||||
/// contexts.
|
||||
class ExternalASTSource {
|
||||
/// \brief Whether this AST source also provides information for
|
||||
/// semantic analysis.
|
||||
bool SemaSource;
|
||||
|
||||
friend class ExternalSemaSource;
|
||||
|
||||
public:
|
||||
ExternalASTSource() : SemaSource(false) { }
|
||||
|
||||
virtual ~ExternalASTSource();
|
||||
|
||||
/// \brief Resolve a type ID into a type, potentially building a new
|
||||
/// type.
|
||||
virtual QualType GetType(uint32_t ID) = 0;
|
||||
|
||||
/// \brief Resolve a declaration ID into a declaration, potentially
|
||||
/// building a new declaration.
|
||||
virtual Decl *GetDecl(uint32_t ID) = 0;
|
||||
|
||||
/// \brief Resolve the offset of a statement in the decl stream into a
|
||||
/// statement.
|
||||
///
|
||||
/// This operation will read a new statement from the external
|
||||
/// source each time it is called, and is meant to be used via a
|
||||
/// LazyOffsetPtr.
|
||||
virtual Stmt *GetDeclStmt(uint64_t Offset) = 0;
|
||||
|
||||
/// \brief Read all of the declarations lexically stored in a
|
||||
/// declaration context.
|
||||
///
|
||||
/// \param DC The declaration context whose declarations will be
|
||||
/// read.
|
||||
///
|
||||
/// \param Decls Vector that will contain the declarations loaded
|
||||
/// from the external source. The caller is responsible for merging
|
||||
/// these declarations with any declarations already stored in the
|
||||
/// declaration context.
|
||||
///
|
||||
/// \returns true if there was an error while reading the
|
||||
/// declarations for this declaration context.
|
||||
virtual bool ReadDeclsLexicallyInContext(DeclContext *DC,
|
||||
llvm::SmallVectorImpl<uint32_t> &Decls) = 0;
|
||||
|
||||
/// \brief Read all of the declarations visible from a declaration
|
||||
/// context.
|
||||
///
|
||||
/// \param DC The declaration context whose visible declarations
|
||||
/// will be read.
|
||||
///
|
||||
/// \param Decls A vector of visible declaration structures,
|
||||
/// providing the mapping from each name visible in the declaration
|
||||
/// context to the declaration IDs of declarations with that name.
|
||||
///
|
||||
/// \returns true if there was an error while reading the
|
||||
/// declarations for this declaration context.
|
||||
virtual bool ReadDeclsVisibleInContext(DeclContext *DC,
|
||||
llvm::SmallVectorImpl<VisibleDeclaration> & Decls) = 0;
|
||||
|
||||
/// \brief Function that will be invoked when we begin parsing a new
|
||||
/// translation unit involving this external AST source.
|
||||
virtual void StartTranslationUnit(ASTConsumer *Consumer) { }
|
||||
|
||||
/// \brief Print any statistics that have been gathered regarding
|
||||
/// the external AST source.
|
||||
virtual void PrintStats();
|
||||
};
|
||||
|
||||
/// \brief A lazy pointer to an AST node (of base type T) that resides
|
||||
/// within an external AST source.
|
||||
///
|
||||
/// The AST node is identified within the external AST source by a
|
||||
/// 63-bit offset, and can be retrieved via an operation on the
|
||||
/// external AST source itself.
|
||||
template<typename T, T* (ExternalASTSource::*Get)(uint64_t Offset)>
|
||||
struct LazyOffsetPtr {
|
||||
/// \brief Either a pointer to an AST node or the offset within the
|
||||
/// external AST source where the AST node can be found.
|
||||
///
|
||||
/// If the low bit is clear, a pointer to the AST node. If the low
|
||||
/// bit is set, the upper 63 bits are the offset.
|
||||
mutable uint64_t Ptr;
|
||||
|
||||
public:
|
||||
LazyOffsetPtr() : Ptr(0) { }
|
||||
|
||||
explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) { }
|
||||
explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) {
|
||||
assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
|
||||
if (Offset == 0)
|
||||
Ptr = 0;
|
||||
}
|
||||
|
||||
LazyOffsetPtr &operator=(T *Ptr) {
|
||||
this->Ptr = reinterpret_cast<uint64_t>(Ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LazyOffsetPtr &operator=(uint64_t Offset) {
|
||||
assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
|
||||
if (Offset == 0)
|
||||
Ptr = 0;
|
||||
else
|
||||
Ptr = (Offset << 1) | 0x01;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Whether this pointer is non-NULL.
|
||||
///
|
||||
/// This operation does not require the AST node to be deserialized.
|
||||
operator bool() const { return Ptr != 0; }
|
||||
|
||||
/// \brief Whether this pointer is currently stored as an offset.
|
||||
bool isOffset() const { return Ptr & 0x01; }
|
||||
|
||||
/// \brief Retrieve the pointer to the AST node that this lazy pointer
|
||||
///
|
||||
/// \param Source the external AST source.
|
||||
///
|
||||
/// \returns a pointer to the AST node.
|
||||
T* get(ExternalASTSource *Source) const {
|
||||
if (isOffset()) {
|
||||
assert(Source &&
|
||||
"Cannot deserialize a lazy pointer without an AST source");
|
||||
Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1));
|
||||
}
|
||||
return reinterpret_cast<T*>(Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A lazy pointer to a statement.
|
||||
typedef LazyOffsetPtr<Stmt, &ExternalASTSource::GetDeclStmt> LazyDeclStmtPtr;
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
183
include/clang/AST/NestedNameSpecifier.h
Normal file
183
include/clang/AST/NestedNameSpecifier.h
Normal file
@ -0,0 +1,183 @@
|
||||
//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- 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 NestedNameSpecifier class, which represents
|
||||
// a C++ nested-name-specifier.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
|
||||
#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
|
||||
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class NamespaceDecl;
|
||||
class IdentifierInfo;
|
||||
class PrintingPolicy;
|
||||
class Type;
|
||||
|
||||
/// \brief Represents a C++ nested name specifier, such as
|
||||
/// "::std::vector<int>::".
|
||||
///
|
||||
/// C++ nested name specifiers are the prefixes to qualified
|
||||
/// namespaces. For example, "foo::" in "foo::x" is a nested name
|
||||
/// specifier. Nested name specifiers are made up of a sequence of
|
||||
/// specifiers, each of which can be a namespace, type, identifier
|
||||
/// (for dependent names), or the global specifier ('::', must be the
|
||||
/// first specifier).
|
||||
class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
/// \brief The nested name specifier that precedes this nested name
|
||||
/// specifier.
|
||||
///
|
||||
/// The pointer is the nested-name-specifier that precedes this
|
||||
/// one. The integer stores one of the first four values of type
|
||||
/// SpecifierKind.
|
||||
llvm::PointerIntPair<NestedNameSpecifier *, 2> Prefix;
|
||||
|
||||
/// \brief The last component in the nested name specifier, which
|
||||
/// can be an identifier, a declaration, or a type.
|
||||
///
|
||||
/// When the pointer is NULL, this specifier represents the global
|
||||
/// specifier '::'. Otherwise, the pointer is one of
|
||||
/// IdentifierInfo*, Namespace*, or Type*, depending on the kind of
|
||||
/// specifier as encoded within the prefix.
|
||||
void* Specifier;
|
||||
|
||||
public:
|
||||
/// \brief The kind of specifier that completes this nested name
|
||||
/// specifier.
|
||||
enum SpecifierKind {
|
||||
/// \brief An identifier, stored as an IdentifierInfo*.
|
||||
Identifier = 0,
|
||||
/// \brief A namespace, stored as a Namespace*.
|
||||
Namespace = 1,
|
||||
/// \brief A type, stored as a Type*.
|
||||
TypeSpec = 2,
|
||||
/// \brief A type that was preceded by the 'template' keyword,
|
||||
/// stored as a Type*.
|
||||
TypeSpecWithTemplate = 3,
|
||||
/// \brief The global specifier '::'. There is no stored value.
|
||||
Global = 4
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief Builds the global specifier.
|
||||
NestedNameSpecifier() : Prefix(0, 0), Specifier(0) { }
|
||||
|
||||
/// \brief Copy constructor used internally to clone nested name
|
||||
/// specifiers.
|
||||
NestedNameSpecifier(const NestedNameSpecifier &Other)
|
||||
: llvm::FoldingSetNode(Other), Prefix(Other.Prefix),
|
||||
Specifier(Other.Specifier) {
|
||||
}
|
||||
|
||||
NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not implement
|
||||
|
||||
/// \brief Either find or insert the given nested name specifier
|
||||
/// mockup in the given context.
|
||||
static NestedNameSpecifier *FindOrInsert(ASTContext &Context,
|
||||
const NestedNameSpecifier &Mockup);
|
||||
|
||||
public:
|
||||
/// \brief Builds a specifier combining a prefix and an identifier.
|
||||
///
|
||||
/// 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,
|
||||
NestedNameSpecifier *Prefix,
|
||||
IdentifierInfo *II);
|
||||
|
||||
/// \brief Builds a nested name specifier that names a namespace.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
NamespaceDecl *NS);
|
||||
|
||||
/// \brief Builds a nested name specifier that names a type.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
bool Template, Type *T);
|
||||
|
||||
/// \brief Returns the nested name specifier representing the global
|
||||
/// scope.
|
||||
static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context);
|
||||
|
||||
/// \brief Return the prefix of this nested name specifier.
|
||||
///
|
||||
/// The prefix contains all of the parts of the nested name
|
||||
/// specifier that preced this current specifier. For example, for a
|
||||
/// nested name specifier that represents "foo::bar::", the current
|
||||
/// specifier will contain "bar::" and the prefix will contain
|
||||
/// "foo::".
|
||||
NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); }
|
||||
|
||||
/// \brief Determine what kind of nested name specifier is stored.
|
||||
SpecifierKind getKind() const {
|
||||
if (Specifier == 0)
|
||||
return Global;
|
||||
return (SpecifierKind)Prefix.getInt();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the identifier stored in this nested name
|
||||
/// specifier.
|
||||
IdentifierInfo *getAsIdentifier() const {
|
||||
if (Prefix.getInt() == Identifier)
|
||||
return (IdentifierInfo *)Specifier;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the namespace stored in this nested name
|
||||
/// specifier.
|
||||
NamespaceDecl *getAsNamespace() const {
|
||||
if (Prefix.getInt() == Namespace)
|
||||
return (NamespaceDecl *)Specifier;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type stored in this nested name specifier.
|
||||
Type *getAsType() const {
|
||||
if (Prefix.getInt() == TypeSpec ||
|
||||
Prefix.getInt() == TypeSpecWithTemplate)
|
||||
return (Type *)Specifier;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Whether this nested name specifier refers to a dependent
|
||||
/// type or not.
|
||||
bool isDependent() const;
|
||||
|
||||
/// \brief Print this nested name specifier to the given output
|
||||
/// stream.
|
||||
void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddPointer(Prefix.getOpaqueValue());
|
||||
ID.AddPointer(Specifier);
|
||||
}
|
||||
|
||||
void Destroy(ASTContext &Context);
|
||||
|
||||
/// \brief Dump the nested name specifier to standard output to aid
|
||||
/// in debugging.
|
||||
void dump();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
24
include/clang/AST/PPCBuiltins.def
Normal file
24
include/clang/AST/PPCBuiltins.def
Normal file
@ -0,0 +1,24 @@
|
||||
//===--- PPCBuiltins.def - PowerPC Builtin function database ----*- 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 PowerPC-specific builtin function database. Users of
|
||||
// this file must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
|
||||
// adding stuff on demand.
|
||||
|
||||
// The format of this database matches clang/AST/Builtins.def.
|
||||
|
||||
// This is just a placeholder, the types and attributes are wrong.
|
||||
BUILTIN(__builtin_altivec_abs_v4sf , "ii" , "nc")
|
||||
// FIXME: Obviously incomplete.
|
||||
|
||||
#undef BUILTIN
|
50
include/clang/AST/ParentMap.h
Normal file
50
include/clang/AST/ParentMap.h
Normal file
@ -0,0 +1,50 @@
|
||||
//===--- ParentMap.h - Mappings from Stmts to their Parents -----*- 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 ParentMap class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_PARENTMAP_H
|
||||
#define LLVM_CLANG_PARENTMAP_H
|
||||
|
||||
namespace clang {
|
||||
class Stmt;
|
||||
class Expr;
|
||||
|
||||
class ParentMap {
|
||||
void* Impl;
|
||||
public:
|
||||
ParentMap(Stmt* ASTRoot);
|
||||
~ParentMap();
|
||||
|
||||
Stmt *getParent(Stmt*) const;
|
||||
Stmt *getParentIgnoreParens(Stmt *) const;
|
||||
|
||||
const Stmt *getParent(const Stmt* S) const {
|
||||
return getParent(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
const Stmt *getParentIgnoreParens(const Stmt *S) const {
|
||||
return getParentIgnoreParens(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
bool hasParent(Stmt* S) const {
|
||||
return getParent(S) != 0;
|
||||
}
|
||||
|
||||
bool isConsumedExpr(Expr *E) const;
|
||||
|
||||
bool isConsumedExpr(const Expr *E) const {
|
||||
return isConsumedExpr(const_cast<Expr*>(E));
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
86
include/clang/AST/PrettyPrinter.h
Normal file
86
include/clang/AST/PrettyPrinter.h
Normal file
@ -0,0 +1,86 @@
|
||||
//===--- PrettyPrinter.h - Classes for aiding with AST printing -*- 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 PrinterHelper interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H
|
||||
#define LLVM_CLANG_AST_PRETTY_PRINTER_H
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class TagDecl;
|
||||
|
||||
class PrinterHelper {
|
||||
public:
|
||||
virtual ~PrinterHelper();
|
||||
virtual bool handledStmt(Stmt* E, llvm::raw_ostream& OS) = 0;
|
||||
};
|
||||
|
||||
/// \brief Describes how types, statements, expressions, and
|
||||
/// declarations should be printed.
|
||||
struct PrintingPolicy {
|
||||
/// \brief Create a default printing policy for C.
|
||||
PrintingPolicy()
|
||||
: Indentation(2), CPlusPlus(false), SuppressSpecifiers(false),
|
||||
SuppressTag(false), SuppressTagKind(false), Dump(false) { }
|
||||
|
||||
/// \brief The number of spaces to use to indent each line.
|
||||
unsigned Indentation : 8;
|
||||
|
||||
/// \brief Whether we're printing C++ code (otherwise, we're
|
||||
/// printing C code).
|
||||
bool CPlusPlus : 1;
|
||||
|
||||
/// \brief Whether we should suppress printing of the actual specifiers for
|
||||
/// the given type or declaration.
|
||||
///
|
||||
/// This flag is only used when we are printing declarators beyond
|
||||
/// the first declarator within a declaration group. For example, given:
|
||||
///
|
||||
/// \code
|
||||
/// const int *x, *y;
|
||||
/// \endcode
|
||||
///
|
||||
/// SuppressSpecifiers will be false when printing the
|
||||
/// declaration for "x", so that we will print "int *x"; it will be
|
||||
/// \c true when we print "y", so that we suppress printing the
|
||||
/// "const int" type specifier and instead only print the "*y".
|
||||
bool SuppressSpecifiers : 1;
|
||||
|
||||
/// \brief Whether type printing should skip printing the actual tag type.
|
||||
///
|
||||
/// This is used when the caller needs to print a tag definition in front
|
||||
/// of the type, as in constructs like the following:
|
||||
///
|
||||
/// \code
|
||||
/// typedef struct { int x, y; } Point;
|
||||
/// \endcode
|
||||
bool SuppressTag : 1;
|
||||
|
||||
/// \brief If we are printing a tag type, suppresses printing of the
|
||||
/// kind of tag, e.g., "struct", "union", "enum".
|
||||
bool SuppressTagKind : 1;
|
||||
|
||||
/// \brief True when we are "dumping" rather than "pretty-printing",
|
||||
/// where dumping involves printing the internal details of the AST
|
||||
/// and pretty-printing involves printing something similar to
|
||||
/// source code.
|
||||
bool Dump : 1;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
103
include/clang/AST/RecordLayout.h
Normal file
103
include/clang/AST/RecordLayout.h
Normal file
@ -0,0 +1,103 @@
|
||||
//===--- RecordLayout.h - Layout information for a struct/union -*- 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 RecordLayout interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_LAYOUTINFO_H
|
||||
#define LLVM_CLANG_AST_LAYOUTINFO_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class RecordDecl;
|
||||
|
||||
/// ASTRecordLayout -
|
||||
/// This class contains layout information for one RecordDecl,
|
||||
/// which is a struct/union/class. The decl represented must be a definition,
|
||||
/// not a forward declaration.
|
||||
/// This class is also used to contain layout information for one
|
||||
/// ObjCInterfaceDecl. FIXME - Find appropriate name.
|
||||
/// These objects are managed by ASTContext.
|
||||
class ASTRecordLayout {
|
||||
uint64_t Size; // Size of record in bits.
|
||||
uint64_t NextOffset; // Next available offset
|
||||
uint64_t *FieldOffsets;
|
||||
unsigned Alignment; // Alignment of record in bits.
|
||||
unsigned FieldCount; // Number of fields
|
||||
friend class ASTContext;
|
||||
|
||||
ASTRecordLayout(uint64_t S = 0, unsigned A = 8)
|
||||
: Size(S), NextOffset(S), Alignment(A), FieldCount(0) {}
|
||||
~ASTRecordLayout() {
|
||||
delete [] FieldOffsets;
|
||||
}
|
||||
|
||||
/// Initialize record layout. N is the number of fields in this record.
|
||||
void InitializeLayout(unsigned N) {
|
||||
FieldCount = N;
|
||||
FieldOffsets = new uint64_t[N];
|
||||
}
|
||||
|
||||
/// Finalize record layout. Adjust record size based on the alignment.
|
||||
void FinalizeLayout(bool ForceNonEmpty = false) {
|
||||
// In C++, records cannot be of size 0.
|
||||
if (ForceNonEmpty && Size == 0)
|
||||
Size = 8;
|
||||
// Finally, round the size of the record up to the alignment of the
|
||||
// record itself.
|
||||
Size = (Size + (Alignment-1)) & ~(Alignment-1);
|
||||
}
|
||||
|
||||
void SetFieldOffset(unsigned FieldNo, uint64_t Offset) {
|
||||
assert (FieldNo < FieldCount && "Invalid Field No");
|
||||
FieldOffsets[FieldNo] = Offset;
|
||||
}
|
||||
|
||||
void SetAlignment(unsigned A) { Alignment = A; }
|
||||
|
||||
/// LayoutField - Field layout. StructPacking is the specified
|
||||
/// packing alignment (maximum alignment) in bits to use for the
|
||||
/// structure, or 0 if no packing alignment is specified.
|
||||
void LayoutField(const FieldDecl *FD, unsigned FieldNo,
|
||||
bool IsUnion, unsigned StructPacking,
|
||||
ASTContext &Context);
|
||||
|
||||
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; }
|
||||
|
||||
/// getSize - Get the record size in bits.
|
||||
uint64_t getSize() const { return Size; }
|
||||
|
||||
/// getFieldCount - Get the number of fields in the layout.
|
||||
unsigned getFieldCount() const { return FieldCount; }
|
||||
|
||||
/// getFieldOffset - Get the offset of the given field index, in
|
||||
/// bits.
|
||||
uint64_t getFieldOffset(unsigned FieldNo) const {
|
||||
assert (FieldNo < FieldCount && "Invalid Field No");
|
||||
return FieldOffsets[FieldNo];
|
||||
}
|
||||
|
||||
/// getNextOffset - Get the next available (unused) offset in the
|
||||
/// structure, in bits.
|
||||
uint64_t getNextOffset() const {
|
||||
return NextOffset;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
1223
include/clang/AST/Stmt.h
Normal file
1223
include/clang/AST/Stmt.h
Normal file
File diff suppressed because it is too large
Load Diff
100
include/clang/AST/StmtCXX.h
Normal file
100
include/clang/AST/StmtCXX.h
Normal file
@ -0,0 +1,100 @@
|
||||
//===--- StmtCXX.h - Classes for representing C++ statements ----*- 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 C++ statement AST node classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMTCXX_H
|
||||
#define LLVM_CLANG_AST_STMTCXX_H
|
||||
|
||||
#include "clang/AST/Stmt.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class VarDecl;
|
||||
|
||||
/// CXXCatchStmt - This represents a C++ catch block.
|
||||
///
|
||||
class CXXCatchStmt : public Stmt {
|
||||
SourceLocation CatchLoc;
|
||||
/// The exception-declaration of the type.
|
||||
VarDecl *ExceptionDecl;
|
||||
/// The handler block.
|
||||
Stmt *HandlerBlock;
|
||||
|
||||
public:
|
||||
CXXCatchStmt(SourceLocation catchLoc, VarDecl *exDecl, Stmt *handlerBlock)
|
||||
: Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl),
|
||||
HandlerBlock(handlerBlock) {}
|
||||
|
||||
virtual void Destroy(ASTContext& Ctx);
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(CatchLoc, HandlerBlock->getLocEnd());
|
||||
}
|
||||
|
||||
SourceLocation getCatchLoc() const { return CatchLoc; }
|
||||
VarDecl *getExceptionDecl() { return ExceptionDecl; }
|
||||
QualType getCaughtType();
|
||||
Stmt *getHandlerBlock() { return HandlerBlock; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXCatchStmtClass;
|
||||
}
|
||||
static bool classof(const CXXCatchStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// CXXTryStmt - A C++ try block, including all handlers.
|
||||
///
|
||||
class CXXTryStmt : public Stmt {
|
||||
SourceLocation TryLoc;
|
||||
// First place is the guarded CompoundStatement. Subsequent are the handlers.
|
||||
// More than three handlers should be rare.
|
||||
llvm::SmallVector<Stmt*, 4> Stmts;
|
||||
|
||||
public:
|
||||
CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
|
||||
Stmt **handlers, unsigned numHandlers);
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(TryLoc, Stmts.back()->getLocEnd());
|
||||
}
|
||||
|
||||
SourceLocation getTryLoc() const { return TryLoc; }
|
||||
|
||||
CompoundStmt *getTryBlock() { return llvm::cast<CompoundStmt>(Stmts[0]); }
|
||||
const CompoundStmt *getTryBlock() const {
|
||||
return llvm::cast<CompoundStmt>(Stmts[0]);
|
||||
}
|
||||
|
||||
unsigned getNumHandlers() const { return Stmts.size() - 1; }
|
||||
CXXCatchStmt *getHandler(unsigned i) {
|
||||
return llvm::cast<CXXCatchStmt>(Stmts[i + 1]);
|
||||
}
|
||||
const CXXCatchStmt *getHandler(unsigned i) const {
|
||||
return llvm::cast<CXXCatchStmt>(Stmts[i + 1]);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXTryStmtClass;
|
||||
}
|
||||
static bool classof(const CXXTryStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
83
include/clang/AST/StmtGraphTraits.h
Normal file
83
include/clang/AST/StmtGraphTraits.h
Normal file
@ -0,0 +1,83 @@
|
||||
//===--- StmtGraphTraits.h - Graph Traits for the class Stmt ----*- 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 a template specialization of llvm::GraphTraits to
|
||||
// treat ASTs (Stmt*) as graphs
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMT_GRAPHTRAITS_H
|
||||
#define LLVM_CLANG_AST_STMT_GRAPHTRAITS_H
|
||||
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//template <typename T> struct GraphTraits;
|
||||
|
||||
|
||||
template <> struct GraphTraits<clang::Stmt*> {
|
||||
typedef clang::Stmt NodeType;
|
||||
typedef clang::Stmt::child_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<clang::Stmt*> nodes_iterator;
|
||||
|
||||
static NodeType* getEntryNode(clang::Stmt* S) { return S; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
if (N) return N->child_begin();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
if (N) return N->child_end();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_begin(clang::Stmt* S) {
|
||||
return df_begin(S);
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(clang::Stmt* S) {
|
||||
return df_end(S);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <> struct GraphTraits<const clang::Stmt*> {
|
||||
typedef const clang::Stmt NodeType;
|
||||
typedef clang::Stmt::const_child_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<const clang::Stmt*> nodes_iterator;
|
||||
|
||||
static NodeType* getEntryNode(const clang::Stmt* S) { return S; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
if (N) return N->child_begin();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
if (N) return N->child_end();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_begin(const clang::Stmt* S) {
|
||||
return df_begin(S);
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(const clang::Stmt* S) {
|
||||
return df_end(S);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
145
include/clang/AST/StmtIterator.h
Normal file
145
include/clang/AST/StmtIterator.h
Normal file
@ -0,0 +1,145 @@
|
||||
//===--- StmtIterator.h - Iterators for Statements ------------------------===//
|
||||
//
|
||||
// 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 StmtIterator and ConstStmtIterator classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMT_ITR_H
|
||||
#define LLVM_CLANG_AST_STMT_ITR_H
|
||||
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class Decl;
|
||||
class VariableArrayType;
|
||||
|
||||
class StmtIteratorBase {
|
||||
protected:
|
||||
enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3,
|
||||
Flags = 0x3 };
|
||||
|
||||
union { Stmt** stmt; Decl* decl; Decl** DGI; };
|
||||
uintptr_t RawVAPtr;
|
||||
Decl** DGE;
|
||||
|
||||
bool inDecl() const {
|
||||
return (RawVAPtr & Flags) == DeclMode;
|
||||
}
|
||||
|
||||
bool inDeclGroup() const {
|
||||
return (RawVAPtr & Flags) == DeclGroupMode;
|
||||
}
|
||||
|
||||
bool inSizeOfTypeVA() const {
|
||||
return (RawVAPtr & Flags) == SizeOfTypeVAMode;
|
||||
}
|
||||
|
||||
bool inStmt() const {
|
||||
return (RawVAPtr & Flags) == 0;
|
||||
}
|
||||
|
||||
VariableArrayType* getVAPtr() const {
|
||||
return reinterpret_cast<VariableArrayType*>(RawVAPtr & ~Flags);
|
||||
}
|
||||
|
||||
void setVAPtr(VariableArrayType* P) {
|
||||
assert (inDecl() || inDeclGroup() || inSizeOfTypeVA());
|
||||
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
|
||||
}
|
||||
|
||||
void NextDecl(bool ImmediateAdvance = true);
|
||||
bool HandleDecl(Decl* D);
|
||||
void NextVA();
|
||||
|
||||
Stmt*& GetDeclExpr() const;
|
||||
|
||||
StmtIteratorBase(Stmt** s) : stmt(s), RawVAPtr(0) {}
|
||||
StmtIteratorBase(Decl* d);
|
||||
StmtIteratorBase(VariableArrayType* t);
|
||||
StmtIteratorBase(Decl** dgi, Decl** dge);
|
||||
StmtIteratorBase() : stmt(NULL), RawVAPtr(0) {}
|
||||
};
|
||||
|
||||
|
||||
template <typename DERIVED, typename REFERENCE>
|
||||
class StmtIteratorImpl : public StmtIteratorBase,
|
||||
public std::iterator<std::forward_iterator_tag,
|
||||
REFERENCE, ptrdiff_t,
|
||||
REFERENCE, REFERENCE> {
|
||||
protected:
|
||||
StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {}
|
||||
public:
|
||||
StmtIteratorImpl() {}
|
||||
StmtIteratorImpl(Stmt** s) : StmtIteratorBase(s) {}
|
||||
StmtIteratorImpl(Decl** dgi, Decl** dge) : StmtIteratorBase(dgi, dge) {}
|
||||
StmtIteratorImpl(Decl* d) : StmtIteratorBase(d) {}
|
||||
StmtIteratorImpl(VariableArrayType* t) : StmtIteratorBase(t) {}
|
||||
|
||||
DERIVED& operator++() {
|
||||
if (inDecl() || inDeclGroup()) {
|
||||
if (getVAPtr()) NextVA();
|
||||
else NextDecl();
|
||||
}
|
||||
else if (inSizeOfTypeVA())
|
||||
NextVA();
|
||||
else
|
||||
++stmt;
|
||||
|
||||
return static_cast<DERIVED&>(*this);
|
||||
}
|
||||
|
||||
DERIVED operator++(int) {
|
||||
DERIVED tmp = static_cast<DERIVED&>(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const DERIVED& RHS) const {
|
||||
return stmt == RHS.stmt && RawVAPtr == RHS.RawVAPtr;
|
||||
}
|
||||
|
||||
bool operator!=(const DERIVED& RHS) const {
|
||||
return stmt != RHS.stmt || RawVAPtr != RHS.RawVAPtr;
|
||||
}
|
||||
|
||||
REFERENCE operator*() const {
|
||||
return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr());
|
||||
}
|
||||
|
||||
REFERENCE operator->() const { return operator*(); }
|
||||
};
|
||||
|
||||
struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
||||
explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {}
|
||||
|
||||
StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {}
|
||||
StmtIterator(Decl** dgi, Decl** dge)
|
||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {}
|
||||
|
||||
StmtIterator(VariableArrayType* t):StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
|
||||
StmtIterator(Decl* D) : StmtIteratorImpl<StmtIterator,Stmt*&>(D) {}
|
||||
};
|
||||
|
||||
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
||||
const Stmt*> {
|
||||
explicit ConstStmtIterator() :
|
||||
StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {}
|
||||
|
||||
ConstStmtIterator(const StmtIterator& RHS) :
|
||||
StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
156
include/clang/AST/StmtNodes.def
Normal file
156
include/clang/AST/StmtNodes.def
Normal file
@ -0,0 +1,156 @@
|
||||
//===-- StmtNodes.def - Metadata about Stmt AST nodes -----------*- 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 AST Node info database.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef FIRST_STMT
|
||||
#define FIRST_STMT(CLASS)
|
||||
#define LAST_STMT(CLASS)
|
||||
#endif
|
||||
|
||||
#ifndef FIRST_EXPR
|
||||
#define FIRST_EXPR(CLASS)
|
||||
#define LAST_EXPR(CLASS)
|
||||
#endif
|
||||
|
||||
#ifndef EXPR
|
||||
# define EXPR(Type, Base) STMT(Type, Base)
|
||||
#endif
|
||||
|
||||
// Normal Statements.
|
||||
STMT(NullStmt , Stmt)
|
||||
FIRST_STMT(NullStmt)
|
||||
STMT(CompoundStmt , Stmt)
|
||||
STMT(CaseStmt , SwitchCase)
|
||||
STMT(DefaultStmt , SwitchCase)
|
||||
STMT(LabelStmt , Stmt)
|
||||
STMT(IfStmt , Stmt)
|
||||
STMT(SwitchStmt , Stmt)
|
||||
STMT(WhileStmt , Stmt)
|
||||
STMT(DoStmt , Stmt)
|
||||
STMT(ForStmt , Stmt)
|
||||
STMT(GotoStmt , Stmt)
|
||||
STMT(IndirectGotoStmt, Stmt)
|
||||
STMT(ContinueStmt , Stmt)
|
||||
STMT(BreakStmt , Stmt)
|
||||
STMT(ReturnStmt , Stmt)
|
||||
STMT(DeclStmt , Stmt)
|
||||
STMT(SwitchCase , Stmt)
|
||||
|
||||
// GNU Stmt Extensions
|
||||
STMT(AsmStmt , Stmt)
|
||||
|
||||
// Obj-C statements
|
||||
STMT(ObjCAtTryStmt , Stmt)
|
||||
STMT(ObjCAtCatchStmt , Stmt)
|
||||
STMT(ObjCAtFinallyStmt , Stmt)
|
||||
STMT(ObjCAtThrowStmt , Stmt)
|
||||
STMT(ObjCAtSynchronizedStmt , Stmt)
|
||||
// Obj-C2 statements
|
||||
STMT(ObjCForCollectionStmt, Stmt)
|
||||
|
||||
// C++ statements
|
||||
STMT(CXXCatchStmt, Stmt)
|
||||
STMT(CXXTryStmt , Stmt)
|
||||
|
||||
LAST_STMT(CXXTryStmt)
|
||||
|
||||
// Expressions.
|
||||
EXPR(Expr , Stmt)
|
||||
FIRST_EXPR(Expr)
|
||||
EXPR(PredefinedExpr , Expr)
|
||||
EXPR(DeclRefExpr , Expr)
|
||||
EXPR(IntegerLiteral , Expr)
|
||||
EXPR(FloatingLiteral , Expr)
|
||||
EXPR(ImaginaryLiteral , Expr)
|
||||
EXPR(StringLiteral , Expr)
|
||||
EXPR(CharacterLiteral , Expr)
|
||||
EXPR(ParenExpr , Expr)
|
||||
EXPR(UnaryOperator , Expr)
|
||||
EXPR(SizeOfAlignOfExpr , Expr)
|
||||
EXPR(ArraySubscriptExpr , Expr)
|
||||
EXPR(CallExpr , Expr)
|
||||
EXPR(MemberExpr , Expr)
|
||||
EXPR(CastExpr , Expr)
|
||||
EXPR(BinaryOperator , Expr)
|
||||
EXPR(CompoundAssignOperator, BinaryOperator)
|
||||
EXPR(ConditionalOperator , Expr)
|
||||
EXPR(ImplicitCastExpr , CastExpr)
|
||||
EXPR(ExplicitCastExpr , CastExpr)
|
||||
EXPR(CStyleCastExpr , ExplicitCastExpr)
|
||||
EXPR(CompoundLiteralExpr , Expr)
|
||||
EXPR(ExtVectorElementExpr , Expr)
|
||||
EXPR(InitListExpr , Expr)
|
||||
EXPR(DesignatedInitExpr , Expr)
|
||||
EXPR(ImplicitValueInitExpr , Expr)
|
||||
EXPR(VAArgExpr , Expr)
|
||||
|
||||
// GNU Extensions.
|
||||
EXPR(AddrLabelExpr , Expr)
|
||||
EXPR(StmtExpr , Expr)
|
||||
EXPR(TypesCompatibleExpr , Expr)
|
||||
EXPR(ChooseExpr , Expr)
|
||||
EXPR(GNUNullExpr , Expr)
|
||||
|
||||
// C++ Expressions.
|
||||
EXPR(CXXOperatorCallExpr , CallExpr)
|
||||
EXPR(CXXMemberCallExpr , CallExpr)
|
||||
EXPR(CXXNamedCastExpr , ExplicitCastExpr)
|
||||
EXPR(CXXStaticCastExpr , CXXNamedCastExpr)
|
||||
EXPR(CXXDynamicCastExpr , CXXNamedCastExpr)
|
||||
EXPR(CXXReinterpretCastExpr , CXXNamedCastExpr)
|
||||
EXPR(CXXConstCastExpr , CXXNamedCastExpr)
|
||||
EXPR(CXXFunctionalCastExpr , ExplicitCastExpr)
|
||||
EXPR(CXXTypeidExpr , Expr)
|
||||
EXPR(CXXBoolLiteralExpr , Expr)
|
||||
EXPR(CXXNullPtrLiteralExpr , Expr)
|
||||
EXPR(CXXThisExpr , Expr)
|
||||
EXPR(CXXThrowExpr , Expr)
|
||||
EXPR(CXXDefaultArgExpr , Expr)
|
||||
EXPR(CXXZeroInitValueExpr , Expr)
|
||||
EXPR(CXXConditionDeclExpr , DeclRefExpr)
|
||||
EXPR(CXXNewExpr , Expr)
|
||||
EXPR(CXXDeleteExpr , Expr)
|
||||
EXPR(UnresolvedFunctionNameExpr , Expr)
|
||||
EXPR(UnaryTypeTraitExpr , Expr)
|
||||
EXPR(QualifiedDeclRefExpr , DeclRefExpr)
|
||||
EXPR(UnresolvedDeclRefExpr , Expr)
|
||||
EXPR(CXXConstructExpr , Expr)
|
||||
EXPR(CXXBindTemporaryExpr , Expr)
|
||||
EXPR(CXXExprWithTemporaries , Expr)
|
||||
EXPR(CXXTemporaryObjectExpr , CXXConstructExpr)
|
||||
EXPR(CXXUnresolvedConstructExpr, Expr)
|
||||
EXPR(CXXUnresolvedMemberExpr, Expr)
|
||||
|
||||
// Obj-C Expressions.
|
||||
EXPR(ObjCStringLiteral , Expr)
|
||||
EXPR(ObjCEncodeExpr , Expr)
|
||||
EXPR(ObjCMessageExpr , Expr)
|
||||
EXPR(ObjCSelectorExpr , Expr)
|
||||
EXPR(ObjCProtocolExpr , Expr)
|
||||
EXPR(ObjCIvarRefExpr , Expr)
|
||||
EXPR(ObjCPropertyRefExpr , Expr)
|
||||
EXPR(ObjCKVCRefExpr , Expr)
|
||||
EXPR(ObjCSuperExpr , Expr)
|
||||
|
||||
// Clang Extensions.
|
||||
EXPR(ShuffleVectorExpr , Expr)
|
||||
EXPR(BlockExpr , Expr)
|
||||
EXPR(BlockDeclRefExpr , Expr)
|
||||
|
||||
LAST_EXPR(BlockDeclRefExpr)
|
||||
|
||||
#undef STMT
|
||||
#undef EXPR
|
||||
#undef FIRST_STMT
|
||||
#undef LAST_STMT
|
||||
#undef FIRST_EXPR
|
||||
#undef LAST_EXPR
|
307
include/clang/AST/StmtObjC.h
Normal file
307
include/clang/AST/StmtObjC.h
Normal file
@ -0,0 +1,307 @@
|
||||
//===--- StmtObjC.h - Classes for representing ObjC statements --*- 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 Objective-C statement AST node classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMTOBJC_H
|
||||
#define LLVM_CLANG_AST_STMTOBJC_H
|
||||
|
||||
#include "clang/AST/Stmt.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// ObjCForCollectionStmt - This represents Objective-c's collection statement;
|
||||
/// represented as 'for (element 'in' collection-expression)' stmt.
|
||||
///
|
||||
class ObjCForCollectionStmt : public Stmt {
|
||||
enum { ELEM, COLLECTION, BODY, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR]; // SubExprs[ELEM] is an expression or declstmt.
|
||||
SourceLocation ForLoc;
|
||||
SourceLocation RParenLoc;
|
||||
public:
|
||||
ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body,
|
||||
SourceLocation FCL, SourceLocation RPL);
|
||||
explicit ObjCForCollectionStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCForCollectionStmtClass, Empty) { }
|
||||
|
||||
Stmt *getElement() { return SubExprs[ELEM]; }
|
||||
Expr *getCollection() {
|
||||
return reinterpret_cast<Expr*>(SubExprs[COLLECTION]);
|
||||
}
|
||||
Stmt *getBody() { return SubExprs[BODY]; }
|
||||
|
||||
const Stmt *getElement() const { return SubExprs[ELEM]; }
|
||||
const Expr *getCollection() const {
|
||||
return reinterpret_cast<Expr*>(SubExprs[COLLECTION]);
|
||||
}
|
||||
const Stmt *getBody() const { return SubExprs[BODY]; }
|
||||
|
||||
void setElement(Stmt *S) { SubExprs[ELEM] = S; }
|
||||
void setCollection(Expr *E) {
|
||||
SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(E);
|
||||
}
|
||||
void setBody(Stmt *S) { SubExprs[BODY] = S; }
|
||||
|
||||
SourceLocation getForLoc() const { return ForLoc; }
|
||||
void setForLoc(SourceLocation Loc) { ForLoc = Loc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCForCollectionStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCForCollectionStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCAtCatchStmt - This represents objective-c's @catch statement.
|
||||
class ObjCAtCatchStmt : public Stmt {
|
||||
private:
|
||||
enum { BODY, NEXT_CATCH, END_EXPR };
|
||||
ParmVarDecl *ExceptionDecl;
|
||||
Stmt *SubExprs[END_EXPR];
|
||||
SourceLocation AtCatchLoc, RParenLoc;
|
||||
|
||||
public:
|
||||
ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc,
|
||||
ParmVarDecl *catchVarDecl,
|
||||
Stmt *atCatchStmt, Stmt *atCatchList);
|
||||
|
||||
explicit ObjCAtCatchStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtCatchStmtClass, Empty) { }
|
||||
|
||||
const Stmt *getCatchBody() const { return SubExprs[BODY]; }
|
||||
Stmt *getCatchBody() { return SubExprs[BODY]; }
|
||||
void setCatchBody(Stmt *S) { SubExprs[BODY] = S; }
|
||||
|
||||
const ObjCAtCatchStmt *getNextCatchStmt() const {
|
||||
return static_cast<const ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
|
||||
}
|
||||
ObjCAtCatchStmt *getNextCatchStmt() {
|
||||
return static_cast<ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
|
||||
}
|
||||
void setNextCatchStmt(Stmt *S) { SubExprs[NEXT_CATCH] = S; }
|
||||
|
||||
const ParmVarDecl *getCatchParamDecl() const {
|
||||
return ExceptionDecl;
|
||||
}
|
||||
ParmVarDecl *getCatchParamDecl() {
|
||||
return ExceptionDecl;
|
||||
}
|
||||
void setCatchParamDecl(ParmVarDecl *D) { ExceptionDecl = D; }
|
||||
|
||||
SourceLocation getAtCatchLoc() const { return AtCatchLoc; }
|
||||
void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
|
||||
bool hasEllipsis() const { return getCatchParamDecl() == 0; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtCatchStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtCatchStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement
|
||||
class ObjCAtFinallyStmt : public Stmt {
|
||||
Stmt *AtFinallyStmt;
|
||||
SourceLocation AtFinallyLoc;
|
||||
public:
|
||||
ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt)
|
||||
: Stmt(ObjCAtFinallyStmtClass),
|
||||
AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {}
|
||||
|
||||
explicit ObjCAtFinallyStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtFinallyStmtClass, Empty) { }
|
||||
|
||||
const Stmt *getFinallyBody() const { return AtFinallyStmt; }
|
||||
Stmt *getFinallyBody() { return AtFinallyStmt; }
|
||||
void setFinallyBody(Stmt *S) { AtFinallyStmt = S; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd());
|
||||
}
|
||||
|
||||
SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; }
|
||||
void setAtFinallyLoc(SourceLocation Loc) { AtFinallyLoc = Loc; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtFinallyStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtFinallyStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCAtTryStmt - This represent objective-c's over-all
|
||||
/// @try ... @catch ... @finally statement.
|
||||
class ObjCAtTryStmt : public Stmt {
|
||||
private:
|
||||
enum { TRY, CATCH, FINALLY, END_EXPR };
|
||||
Stmt* SubStmts[END_EXPR];
|
||||
|
||||
SourceLocation AtTryLoc;
|
||||
public:
|
||||
ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
|
||||
Stmt *atCatchStmt,
|
||||
Stmt *atFinallyStmt)
|
||||
: Stmt(ObjCAtTryStmtClass) {
|
||||
SubStmts[TRY] = atTryStmt;
|
||||
SubStmts[CATCH] = atCatchStmt;
|
||||
SubStmts[FINALLY] = atFinallyStmt;
|
||||
AtTryLoc = atTryLoc;
|
||||
}
|
||||
explicit ObjCAtTryStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtTryStmtClass, Empty) { }
|
||||
|
||||
SourceLocation getAtTryLoc() const { return AtTryLoc; }
|
||||
void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; }
|
||||
|
||||
const Stmt *getTryBody() const { return SubStmts[TRY]; }
|
||||
Stmt *getTryBody() { return SubStmts[TRY]; }
|
||||
void setTryBody(Stmt *S) { SubStmts[TRY] = S; }
|
||||
|
||||
const ObjCAtCatchStmt *getCatchStmts() const {
|
||||
return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
|
||||
}
|
||||
ObjCAtCatchStmt *getCatchStmts() {
|
||||
return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
|
||||
}
|
||||
void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; }
|
||||
|
||||
const ObjCAtFinallyStmt *getFinallyStmt() const {
|
||||
return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
|
||||
}
|
||||
ObjCAtFinallyStmt *getFinallyStmt() {
|
||||
return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
|
||||
}
|
||||
void setFinallyStmt(Stmt *S) { SubStmts[FINALLY] = S; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd());
|
||||
}
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
/// ObjCAtSynchronizedStmt - This is for objective-c's @synchronized statement.
|
||||
/// Example: @synchronized (sem) {
|
||||
/// do-something;
|
||||
/// }
|
||||
///
|
||||
class ObjCAtSynchronizedStmt : public Stmt {
|
||||
private:
|
||||
enum { SYNC_EXPR, SYNC_BODY, END_EXPR };
|
||||
Stmt* SubStmts[END_EXPR];
|
||||
SourceLocation AtSynchronizedLoc;
|
||||
|
||||
public:
|
||||
ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr,
|
||||
Stmt *synchBody)
|
||||
: Stmt(ObjCAtSynchronizedStmtClass) {
|
||||
SubStmts[SYNC_EXPR] = synchExpr;
|
||||
SubStmts[SYNC_BODY] = synchBody;
|
||||
AtSynchronizedLoc = atSynchronizedLoc;
|
||||
}
|
||||
explicit ObjCAtSynchronizedStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtSynchronizedStmtClass, Empty) { }
|
||||
|
||||
SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; }
|
||||
void setAtSynchronizedLoc(SourceLocation Loc) { AtSynchronizedLoc = Loc; }
|
||||
|
||||
const CompoundStmt *getSynchBody() const {
|
||||
return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]);
|
||||
}
|
||||
CompoundStmt *getSynchBody() {
|
||||
return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]);
|
||||
}
|
||||
void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; }
|
||||
|
||||
const Expr *getSynchExpr() const {
|
||||
return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
|
||||
}
|
||||
Expr *getSynchExpr() {
|
||||
return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
|
||||
}
|
||||
void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtSynchronizedStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtSynchronizedStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCAtThrowStmt - This represents objective-c's @throw statement.
|
||||
class ObjCAtThrowStmt : public Stmt {
|
||||
Stmt *Throw;
|
||||
SourceLocation AtThrowLoc;
|
||||
public:
|
||||
ObjCAtThrowStmt(SourceLocation atThrowLoc, Stmt *throwExpr)
|
||||
: Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) {
|
||||
AtThrowLoc = atThrowLoc;
|
||||
}
|
||||
explicit ObjCAtThrowStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtThrowStmtClass, Empty) { }
|
||||
|
||||
const Expr *getThrowExpr() const { return reinterpret_cast<Expr*>(Throw); }
|
||||
Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); }
|
||||
void setThrowExpr(Stmt *S) { Throw = S; }
|
||||
|
||||
SourceLocation getThrowLoc() { return AtThrowLoc; }
|
||||
void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
if (Throw)
|
||||
return SourceRange(AtThrowLoc, Throw->getLocEnd());
|
||||
else
|
||||
return SourceRange(AtThrowLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtThrowStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtThrowStmt *) { return true; }
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
176
include/clang/AST/StmtVisitor.h
Normal file
176
include/clang/AST/StmtVisitor.h
Normal file
@ -0,0 +1,176 @@
|
||||
//===--- StmtVisitor.h - Visitor for Stmt subclasses ------------*- 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 StmtVisitor interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMTVISITOR_H
|
||||
#define LLVM_CLANG_AST_STMTVISITOR_H
|
||||
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
#define DISPATCH(NAME, CLASS) \
|
||||
return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<CLASS*>(S))
|
||||
|
||||
/// StmtVisitor - This class implements a simple visitor for Stmt subclasses.
|
||||
/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
|
||||
template<typename ImplClass, typename RetTy=void>
|
||||
class StmtVisitor {
|
||||
public:
|
||||
RetTy Visit(Stmt *S) {
|
||||
|
||||
// If we have a binary expr, dispatch to the subcode of the binop. A smart
|
||||
// optimizer (e.g. LLVM) will fold this comparison into the switch stmt
|
||||
// below.
|
||||
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
|
||||
switch (BinOp->getOpcode()) {
|
||||
default: assert(0 && "Unknown binary operator!");
|
||||
case BinaryOperator::PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator);
|
||||
case BinaryOperator::PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator);
|
||||
case BinaryOperator::Mul: DISPATCH(BinMul, BinaryOperator);
|
||||
case BinaryOperator::Div: DISPATCH(BinDiv, BinaryOperator);
|
||||
case BinaryOperator::Rem: DISPATCH(BinRem, BinaryOperator);
|
||||
case BinaryOperator::Add: DISPATCH(BinAdd, BinaryOperator);
|
||||
case BinaryOperator::Sub: DISPATCH(BinSub, BinaryOperator);
|
||||
case BinaryOperator::Shl: DISPATCH(BinShl, BinaryOperator);
|
||||
case BinaryOperator::Shr: DISPATCH(BinShr, BinaryOperator);
|
||||
|
||||
case BinaryOperator::LT: DISPATCH(BinLT, BinaryOperator);
|
||||
case BinaryOperator::GT: DISPATCH(BinGT, BinaryOperator);
|
||||
case BinaryOperator::LE: DISPATCH(BinLE, BinaryOperator);
|
||||
case BinaryOperator::GE: DISPATCH(BinGE, BinaryOperator);
|
||||
case BinaryOperator::EQ: DISPATCH(BinEQ, BinaryOperator);
|
||||
case BinaryOperator::NE: DISPATCH(BinNE, BinaryOperator);
|
||||
|
||||
case BinaryOperator::And: DISPATCH(BinAnd, BinaryOperator);
|
||||
case BinaryOperator::Xor: DISPATCH(BinXor, BinaryOperator);
|
||||
case BinaryOperator::Or : DISPATCH(BinOr, BinaryOperator);
|
||||
case BinaryOperator::LAnd: DISPATCH(BinLAnd, BinaryOperator);
|
||||
case BinaryOperator::LOr : DISPATCH(BinLOr, BinaryOperator);
|
||||
case BinaryOperator::Assign: DISPATCH(BinAssign, BinaryOperator);
|
||||
case BinaryOperator::MulAssign:
|
||||
DISPATCH(BinMulAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::DivAssign:
|
||||
DISPATCH(BinDivAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::RemAssign:
|
||||
DISPATCH(BinRemAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::AddAssign:
|
||||
DISPATCH(BinAddAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::SubAssign:
|
||||
DISPATCH(BinSubAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::ShlAssign:
|
||||
DISPATCH(BinShlAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::ShrAssign:
|
||||
DISPATCH(BinShrAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::AndAssign:
|
||||
DISPATCH(BinAndAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::OrAssign:
|
||||
DISPATCH(BinOrAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::XorAssign:
|
||||
DISPATCH(BinXorAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::Comma: DISPATCH(BinComma, BinaryOperator);
|
||||
}
|
||||
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
|
||||
switch (UnOp->getOpcode()) {
|
||||
default: assert(0 && "Unknown unary operator!");
|
||||
case UnaryOperator::PostInc: DISPATCH(UnaryPostInc, UnaryOperator);
|
||||
case UnaryOperator::PostDec: DISPATCH(UnaryPostDec, UnaryOperator);
|
||||
case UnaryOperator::PreInc: DISPATCH(UnaryPreInc, UnaryOperator);
|
||||
case UnaryOperator::PreDec: DISPATCH(UnaryPreDec, UnaryOperator);
|
||||
case UnaryOperator::AddrOf: DISPATCH(UnaryAddrOf, UnaryOperator);
|
||||
case UnaryOperator::Deref: DISPATCH(UnaryDeref, UnaryOperator);
|
||||
case UnaryOperator::Plus: DISPATCH(UnaryPlus, UnaryOperator);
|
||||
case UnaryOperator::Minus: DISPATCH(UnaryMinus, UnaryOperator);
|
||||
case UnaryOperator::Not: DISPATCH(UnaryNot, UnaryOperator);
|
||||
case UnaryOperator::LNot: DISPATCH(UnaryLNot, UnaryOperator);
|
||||
case UnaryOperator::Real: DISPATCH(UnaryReal, UnaryOperator);
|
||||
case UnaryOperator::Imag: DISPATCH(UnaryImag, UnaryOperator);
|
||||
case UnaryOperator::Extension: DISPATCH(UnaryExtension, UnaryOperator);
|
||||
case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator);
|
||||
}
|
||||
}
|
||||
|
||||
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
|
||||
switch (S->getStmtClass()) {
|
||||
default: assert(0 && "Unknown stmt kind!");
|
||||
#define STMT(CLASS, PARENT) \
|
||||
case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS);
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
}
|
||||
}
|
||||
|
||||
// If the implementation chooses not to implement a certain visit method, fall
|
||||
// back on VisitExpr or whatever else is the superclass.
|
||||
#define STMT(CLASS, PARENT) \
|
||||
RetTy Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT); }
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
|
||||
// If the implementation doesn't implement binary operator methods, fall back
|
||||
// on VisitBinaryOperator.
|
||||
#define BINOP_FALLBACK(NAME) \
|
||||
RetTy VisitBin ## NAME(BinaryOperator *S) { \
|
||||
DISPATCH(BinaryOperator, BinaryOperator); \
|
||||
}
|
||||
BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI)
|
||||
BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem)
|
||||
BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl)
|
||||
BINOP_FALLBACK(Shr)
|
||||
|
||||
BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE)
|
||||
BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE)
|
||||
BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or)
|
||||
BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr)
|
||||
|
||||
BINOP_FALLBACK(Assign)
|
||||
BINOP_FALLBACK(Comma)
|
||||
#undef BINOP_FALLBACK
|
||||
|
||||
// If the implementation doesn't implement compound assignment operator
|
||||
// methods, fall back on VisitCompoundAssignOperator.
|
||||
#define CAO_FALLBACK(NAME) \
|
||||
RetTy VisitBin ## NAME(CompoundAssignOperator *S) { \
|
||||
DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \
|
||||
}
|
||||
CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign)
|
||||
CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign)
|
||||
CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign)
|
||||
CAO_FALLBACK(XorAssign)
|
||||
#undef CAO_FALLBACK
|
||||
|
||||
// If the implementation doesn't implement unary operator methods, fall back
|
||||
// on VisitUnaryOperator.
|
||||
#define UNARYOP_FALLBACK(NAME) \
|
||||
RetTy VisitUnary ## NAME(UnaryOperator *S) { \
|
||||
DISPATCH(UnaryOperator, UnaryOperator); \
|
||||
}
|
||||
UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec)
|
||||
UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec)
|
||||
UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref)
|
||||
|
||||
UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus)
|
||||
UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot)
|
||||
UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag)
|
||||
UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf)
|
||||
#undef UNARYOP_FALLBACK
|
||||
|
||||
// Base case, ignore it. :)
|
||||
RetTy VisitStmt(Stmt *Node) { return RetTy(); }
|
||||
};
|
||||
|
||||
#undef DISPATCH
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
38
include/clang/AST/TargetBuiltins.h
Normal file
38
include/clang/AST/TargetBuiltins.h
Normal file
@ -0,0 +1,38 @@
|
||||
//===--- TargetBuiltins.h - Target specific builtin IDs -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_TARGET_BUILTINS_H
|
||||
#define LLVM_CLANG_AST_TARGET_BUILTINS_H
|
||||
|
||||
#include "clang/AST/Builtins.h"
|
||||
#undef PPC
|
||||
|
||||
namespace clang {
|
||||
/// X86 builtins
|
||||
namespace X86 {
|
||||
enum {
|
||||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "X86Builtins.def"
|
||||
LastTSBuiltin
|
||||
};
|
||||
}
|
||||
|
||||
/// PPC builtins
|
||||
namespace PPC {
|
||||
enum {
|
||||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "PPCBuiltins.def"
|
||||
LastTSBuiltin
|
||||
};
|
||||
}
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
258
include/clang/AST/TemplateName.h
Normal file
258
include/clang/AST/TemplateName.h
Normal file
@ -0,0 +1,258 @@
|
||||
//===--- TemplateName.h - C++ Template Name Representation-------*- 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 TemplateName interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_TEMPLATENAME_H
|
||||
#define LLVM_CLANG_AST_TEMPLATENAME_H
|
||||
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class DependentTemplateName;
|
||||
class IdentifierInfo;
|
||||
class NestedNameSpecifier;
|
||||
class PrintingPolicy;
|
||||
class QualifiedTemplateName;
|
||||
class TemplateDecl;
|
||||
|
||||
/// \brief Represents a C++ template name within the type system.
|
||||
///
|
||||
/// A C++ template name refers to a template within the C++ type
|
||||
/// system. In most cases, a template name is simply a reference to a
|
||||
/// class template, e.g.
|
||||
///
|
||||
/// \code
|
||||
/// template<typename T> class X { };
|
||||
///
|
||||
/// X<int> xi;
|
||||
/// \endcode
|
||||
///
|
||||
/// Here, the 'X' in \c X<int> is a template name that refers to the
|
||||
/// declaration of the class template X, above. Template names can
|
||||
/// also refer to function templates, C++0x template aliases, etc.
|
||||
///
|
||||
/// Some template names are dependent. For example, consider:
|
||||
///
|
||||
/// \code
|
||||
/// template<typename MetaFun, typename T1, typename T2> struct apply2 {
|
||||
/// typedef typename MetaFun::template apply<T1, T2>::type type;
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// Here, "apply" is treated as a template name within the typename
|
||||
/// specifier in the typedef. "apply" is a nested template, and can
|
||||
/// only be understood in the context of
|
||||
class TemplateName {
|
||||
typedef llvm::PointerUnion3<TemplateDecl *, QualifiedTemplateName *,
|
||||
DependentTemplateName *> StorageType;
|
||||
|
||||
StorageType Storage;
|
||||
|
||||
explicit TemplateName(void *Ptr) {
|
||||
Storage = StorageType::getFromOpaqueValue(Ptr);
|
||||
}
|
||||
|
||||
public:
|
||||
TemplateName() : Storage() { }
|
||||
explicit TemplateName(TemplateDecl *Template) : Storage(Template) { }
|
||||
explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { }
|
||||
explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { }
|
||||
|
||||
/// \brief Retrieve the the underlying template declaration that
|
||||
/// this template name refers to, if known.
|
||||
///
|
||||
/// \returns The template declaration that this template name refers
|
||||
/// to, if any. If the template name does not refer to a specific
|
||||
/// declaration because it is a dependent name, returns NULL.
|
||||
TemplateDecl *getAsTemplateDecl() const;
|
||||
|
||||
/// \brief Retrieve the underlying qualified template name
|
||||
/// structure, if any.
|
||||
QualifiedTemplateName *getAsQualifiedTemplateName() const {
|
||||
return Storage.dyn_cast<QualifiedTemplateName *>();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the underlying dependent template name
|
||||
/// structure, if any.
|
||||
DependentTemplateName *getAsDependentTemplateName() const {
|
||||
return Storage.dyn_cast<DependentTemplateName *>();
|
||||
}
|
||||
|
||||
/// \brief Determines whether this is a dependent template name.
|
||||
bool isDependent() const;
|
||||
|
||||
/// \brief Print the template name.
|
||||
///
|
||||
/// \param OS the output stream to which the template name will be
|
||||
/// printed.
|
||||
///
|
||||
/// \param SuppressNNS if true, don't print the
|
||||
/// nested-name-specifier that precedes the template name (if it has
|
||||
/// one).
|
||||
void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
bool SuppressNNS = false) const;
|
||||
|
||||
/// \brief Debugging aid that dumps the template name to standard
|
||||
/// error.
|
||||
void dump() const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
ID.AddPointer(Storage.getOpaqueValue());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template name as a void pointer.
|
||||
void *getAsVoidPointer() const { return Storage.getOpaqueValue(); }
|
||||
|
||||
/// \brief Build a template name from a void pointer.
|
||||
static TemplateName getFromVoidPointer(void *Ptr) {
|
||||
return TemplateName(Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a template name that was expressed as a
|
||||
/// qualified name.
|
||||
///
|
||||
/// This kind of template name refers to a template name that was
|
||||
/// preceded by a nested name specifier, e.g., \c std::vector. Here,
|
||||
/// the nested name specifier is "std::" and the template name is the
|
||||
/// declaration for "vector". The QualifiedTemplateName class is only
|
||||
/// used to provide "sugar" for template names that were expressed
|
||||
/// with a qualified name, and has no semantic meaning. In this
|
||||
/// manner, it is to TemplateName what QualifiedNameType is to Type,
|
||||
/// providing extra syntactic sugar for downstream clients.
|
||||
class QualifiedTemplateName : public llvm::FoldingSetNode {
|
||||
/// \brief The nested name specifier that qualifies the template name.
|
||||
///
|
||||
/// The bit is used to indicate whether the "template" keyword was
|
||||
/// present before the template name itself. Note that the
|
||||
/// "template" keyword is always redundant in this case (otherwise,
|
||||
/// the template name would be a dependent name and we would express
|
||||
/// this name with DependentTemplateName).
|
||||
llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier;
|
||||
|
||||
/// \brief The template declaration that this qualified name refers
|
||||
/// to.
|
||||
TemplateDecl *Template;
|
||||
|
||||
friend class ASTContext;
|
||||
|
||||
QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword,
|
||||
TemplateDecl *Template)
|
||||
: Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) { }
|
||||
|
||||
public:
|
||||
/// \brief Return the nested name specifier that qualifies this name.
|
||||
NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); }
|
||||
|
||||
/// \brief Whether the template name was prefixed by the "template"
|
||||
/// keyword.
|
||||
bool hasTemplateKeyword() const { return Qualifier.getInt(); }
|
||||
|
||||
/// \brief The template declaration to which this qualified name
|
||||
/// refers.
|
||||
TemplateDecl *getTemplateDecl() const { return Template; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
|
||||
bool TemplateKeyword, TemplateDecl *Template) {
|
||||
ID.AddPointer(NNS);
|
||||
ID.AddBoolean(TemplateKeyword);
|
||||
ID.AddPointer(Template);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a dependent template name that cannot be
|
||||
/// resolved prior to template instantiation.
|
||||
///
|
||||
/// This kind of template name refers to a dependent template name,
|
||||
/// including its nested name specifier. For example,
|
||||
/// DependentTemplateName can refer to "MetaFun::template apply",
|
||||
/// where "MetaFun::" is the nested name specifier and "apply" is the
|
||||
/// template name referenced. The "template" keyword is implied.
|
||||
class DependentTemplateName : public llvm::FoldingSetNode {
|
||||
/// \brief The nested name specifier that qualifies the template
|
||||
/// name.
|
||||
NestedNameSpecifier *Qualifier;
|
||||
|
||||
/// \brief The dependent template name.
|
||||
const IdentifierInfo *Name;
|
||||
|
||||
/// \brief The canonical template name to which this dependent
|
||||
/// template name refers.
|
||||
///
|
||||
/// The canonical template name for a dependent template name is
|
||||
/// another dependent template name whose nested name specifier is
|
||||
/// canonical.
|
||||
TemplateName CanonicalTemplateName;
|
||||
|
||||
friend class ASTContext;
|
||||
|
||||
DependentTemplateName(NestedNameSpecifier *Qualifier,
|
||||
const IdentifierInfo *Name)
|
||||
: Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { }
|
||||
|
||||
DependentTemplateName(NestedNameSpecifier *Qualifier,
|
||||
const IdentifierInfo *Name,
|
||||
TemplateName Canon)
|
||||
: Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { }
|
||||
|
||||
public:
|
||||
/// \brief Return the nested name specifier that qualifies this name.
|
||||
NestedNameSpecifier *getQualifier() const { return Qualifier; }
|
||||
|
||||
/// \brief Return the name to which this dependent template name
|
||||
/// refers.
|
||||
const IdentifierInfo *getName() const { return Name; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getQualifier(), getName());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name) {
|
||||
ID.AddPointer(NNS);
|
||||
ID.AddPointer(Name);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// \brief The clang::TemplateName class is effectively a pointer.
|
||||
template<>
|
||||
class PointerLikeTypeTraits<clang::TemplateName> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(clang::TemplateName TN) {
|
||||
return TN.getAsVoidPointer();
|
||||
}
|
||||
|
||||
static inline clang::TemplateName getFromVoidPointer(void *Ptr) {
|
||||
return clang::TemplateName::getFromVoidPointer(Ptr);
|
||||
}
|
||||
|
||||
// No bits are available!
|
||||
enum { NumLowBitsAvailable = 0 };
|
||||
};
|
||||
|
||||
} // end namespace llvm.
|
||||
|
||||
#endif
|
1977
include/clang/AST/Type.h
Normal file
1977
include/clang/AST/Type.h
Normal file
File diff suppressed because it is too large
Load Diff
85
include/clang/AST/TypeNodes.def
Normal file
85
include/clang/AST/TypeNodes.def
Normal file
@ -0,0 +1,85 @@
|
||||
//===-- TypeNodes.def - Metadata about Type AST nodes -----------*- 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 AST type info database. Each type node is
|
||||
// enumerated by providing its name (e.g., "Builtin" or "Enum") and
|
||||
// base class (e.g., "Type" or "TagType"). Depending on where in the
|
||||
// abstract syntax tree the type will show up, the enumeration uses
|
||||
// one of four different macros:
|
||||
//
|
||||
// TYPE(Class, Base) - A type that can show up anywhere in the AST,
|
||||
// and might be dependent, canonical, or non-canonical. All clients
|
||||
// will need to understand these types.
|
||||
//
|
||||
// ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in
|
||||
// the type hierarchy but has no concrete instances.
|
||||
//
|
||||
// NON_CANONICAL_TYPE(Class, Base) - A type that can show up
|
||||
// anywhere in the AST but will never be a part of a canonical
|
||||
// type. Clients that only need to deal with canonical types
|
||||
// (ignoring, e.g., typedefs and other type alises used for
|
||||
// pretty-printing) can ignore these types.
|
||||
//
|
||||
// DEPENDENT_TYPE(Class, Base) - A type that will only show up
|
||||
// within a C++ template that has not been instantiated, e.g., a
|
||||
// type that is always dependent. Clients that do not need to deal
|
||||
// with uninstantiated C++ templates can ignore these types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ABSTRACT_TYPE
|
||||
# define ABSTRACT_TYPE(Class, Base) TYPE(Class, Base)
|
||||
#endif
|
||||
|
||||
#ifndef NON_CANONICAL_TYPE
|
||||
# define NON_CANONICAL_TYPE(Class, Base) TYPE(Class, Base)
|
||||
#endif
|
||||
|
||||
#ifndef DEPENDENT_TYPE
|
||||
# define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base)
|
||||
#endif
|
||||
|
||||
TYPE(ExtQual, Type)
|
||||
TYPE(Builtin, Type)
|
||||
TYPE(FixedWidthInt, Type)
|
||||
TYPE(Complex, Type)
|
||||
TYPE(Pointer, Type)
|
||||
TYPE(BlockPointer, Type)
|
||||
ABSTRACT_TYPE(Reference, Type)
|
||||
TYPE(LValueReference, ReferenceType)
|
||||
TYPE(RValueReference, ReferenceType)
|
||||
TYPE(MemberPointer, Type)
|
||||
ABSTRACT_TYPE(Array, Type)
|
||||
TYPE(ConstantArray, ArrayType)
|
||||
TYPE(IncompleteArray, ArrayType)
|
||||
TYPE(VariableArray, ArrayType)
|
||||
DEPENDENT_TYPE(DependentSizedArray, ArrayType)
|
||||
TYPE(Vector, Type)
|
||||
TYPE(ExtVector, VectorType)
|
||||
ABSTRACT_TYPE(Function, Type)
|
||||
TYPE(FunctionProto, FunctionType)
|
||||
TYPE(FunctionNoProto, FunctionType)
|
||||
NON_CANONICAL_TYPE(Typedef, Type)
|
||||
NON_CANONICAL_TYPE(TypeOfExpr, Type)
|
||||
NON_CANONICAL_TYPE(TypeOf, Type)
|
||||
ABSTRACT_TYPE(Tag, Type)
|
||||
TYPE(Record, TagType)
|
||||
TYPE(Enum, TagType)
|
||||
DEPENDENT_TYPE(TemplateTypeParm, Type)
|
||||
TYPE(TemplateSpecialization, Type)
|
||||
NON_CANONICAL_TYPE(QualifiedName, Type)
|
||||
DEPENDENT_TYPE(Typename, Type)
|
||||
TYPE(ObjCInterface, Type)
|
||||
TYPE(ObjCQualifiedInterface, ObjCInterfaceType)
|
||||
TYPE(ObjCQualifiedId, Type)
|
||||
|
||||
#undef DEPENDENT_TYPE
|
||||
#undef NON_CANONICAL_TYPE
|
||||
#undef ABSTRACT_TYPE
|
||||
#undef TYPE
|
63
include/clang/AST/TypeOrdering.h
Normal file
63
include/clang/AST/TypeOrdering.h
Normal file
@ -0,0 +1,63 @@
|
||||
//===-------------- TypeOrdering.h - Total ordering for types -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides a function objects and specializations that
|
||||
// allow QualType values to be sorted, used in std::maps, std::sets,
|
||||
// llvm::DenseMaps, and llvm::DenseSets.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TYPE_ORDERING_H
|
||||
#define LLVM_CLANG_TYPE_ORDERING_H
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include <functional>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// QualTypeOrdering - Function object that provides a total ordering
|
||||
/// on QualType values.
|
||||
struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
|
||||
bool operator()(QualType T1, QualType T2) const {
|
||||
return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
template<class> struct DenseMapInfo;
|
||||
|
||||
template<> struct DenseMapInfo<clang::QualType> {
|
||||
static inline clang::QualType getEmptyKey() { return clang::QualType(); }
|
||||
|
||||
static inline clang::QualType getTombstoneKey() {
|
||||
using clang::QualType;
|
||||
return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1));
|
||||
}
|
||||
|
||||
static unsigned getHashValue(clang::QualType Val) {
|
||||
return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^
|
||||
((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9));
|
||||
}
|
||||
|
||||
static bool isEqual(clang::QualType LHS, clang::QualType RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
|
||||
static bool isPod() {
|
||||
// QualType isn't *technically* a POD type. However, we can get
|
||||
// away with calling it a POD type since its copy constructor,
|
||||
// copy assignment operator, and destructor are all trivial.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
427
include/clang/AST/X86Builtins.def
Normal file
427
include/clang/AST/X86Builtins.def
Normal file
@ -0,0 +1,427 @@
|
||||
//===--- X86Builtins.def - X86 Builtin function database --------*- 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 X86-specific builtin function database. Users of
|
||||
// this file must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
|
||||
// adding stuff on demand.
|
||||
|
||||
// The format of this database matches clang/AST/Builtins.def.
|
||||
|
||||
// FIXME: In GCC, these builtins are defined depending on whether support for
|
||||
// MMX/SSE/etc is turned on. We should do this too.
|
||||
|
||||
// FIXME: Ideally we would be able to pull this information from what
|
||||
// LLVM already knows about X86 builtins. We need to match the LLVM
|
||||
// definition anyway, since code generation will lower to the
|
||||
// intrinsic if one exists.
|
||||
|
||||
BUILTIN(__builtin_ia32_emms , "v", "")
|
||||
|
||||
// FIXME: Are these nothrow/const?
|
||||
|
||||
// SSE intrinsics.
|
||||
BUILTIN(__builtin_ia32_comieq, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comilt, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comile, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comigt, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comige, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comineq, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomieq, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomilt, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomile, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomigt, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomige, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomineq, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comisdeq, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdlt, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdle, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdgt, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdge, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdneq, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdeq, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdlt, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdle, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_addps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_subps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_mulps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_divps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_addss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_subss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_mulss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_divss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fc", "")
|
||||
BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fc", "")
|
||||
BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_andps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_andnps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_orps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_xorps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_movss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_movhlps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_movlhps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_unpckhps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_unpcklps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psubusw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pmullw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhuw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pand, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pandn, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_por, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pxor, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pavgb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pavgw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_punpcklbw, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_punpcklwd, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_punpckldq, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_addpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_subpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_mulpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_divpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_addsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_subsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_mulsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_divsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dc", "")
|
||||
BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dc", "")
|
||||
BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_maxsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_andpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_andnpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_orpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_xorpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_movsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_unpckhpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_unpcklpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_paddb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_paddw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_paddd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_paddq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_psubb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psubw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psubd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psubq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_paddsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_paddsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psubsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psubsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_paddusb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmullw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pand128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pandn128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_por128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pxor128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pminsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhbw128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_punpckhwd128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhdq128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_punpckhqdq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_punpcklbw128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_punpcklwd128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_punpckldq128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_punpcklqdq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_packsswb128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_packssdw128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_packuswb128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhuw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_addsubps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_addsubpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_haddps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_haddpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_hsubps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_hsubpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_phaddw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_phaddd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pmaddubsw128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psignw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psignd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_pabsb128, "V16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pabsw128, "V8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pabsd128, "V4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_psllw, "V4sV4sV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pslld, "V2iV2iV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psllq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrlw, "V4sV4sV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrld, "V2iV2iV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrlq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psraw, "V4sV4sV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrad, "V2iV2iV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pshufw, "V4sV4si", "")
|
||||
BUILTIN(__builtin_ia32_pmaddwd, "V2iV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_ldmxcsr, "vUi", "")
|
||||
BUILTIN(__builtin_ia32_stmxcsr, "Ui", "")
|
||||
BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi2ss, "V4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi642ss, "V4fV4fLLi", "")
|
||||
BUILTIN(__builtin_ia32_cvtss2si, "iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtss2si64, "LLiV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttss2si, "iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttss2si64, "LLiV4f", "")
|
||||
BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "")
|
||||
BUILTIN(__builtin_ia32_loadups, "V4ffC*", "")
|
||||
BUILTIN(__builtin_ia32_storeups, "vf*V4f", "")
|
||||
BUILTIN(__builtin_ia32_loadhps, "V4fV4fV2i*", "")
|
||||
BUILTIN(__builtin_ia32_loadlps, "V4fV4fV2i*", "")
|
||||
BUILTIN(__builtin_ia32_storehps, "vV2i*V4f", "")
|
||||
BUILTIN(__builtin_ia32_storelps, "vV2i*V4f", "")
|
||||
BUILTIN(__builtin_ia32_movmskps, "iV4f", "")
|
||||
BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "")
|
||||
BUILTIN(__builtin_ia32_movntps, "vf*V4f", "")
|
||||
BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "")
|
||||
BUILTIN(__builtin_ia32_sfence, "v", "")
|
||||
BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_rcpps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_rcpss, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_rsqrtps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_rsqrtss, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_sqrtps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_sqrtss, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_shufps, "V4fV4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_femms, "v", "")
|
||||
BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfadd, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfcmpeq, "V2iV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfcmpge, "V2iV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfcmpgt, "V2iV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfmax, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfmin, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfmul, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrcp, "V2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrcpit1, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrcpit2, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrsqrt, "V2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrsqit1, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "")
|
||||
BUILTIN(__builtin_ia32_pmulhrw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pf2iw, "V2iV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfnacc, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfpnacc, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pi2fw, "V2fV2i", "")
|
||||
BUILTIN(__builtin_ia32_pswapdsf, "V2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_maskmovdqu, "vV16cV16cc*", "")
|
||||
BUILTIN(__builtin_ia32_loadupd, "V2ddC*", "")
|
||||
BUILTIN(__builtin_ia32_storeupd, "vd*V2d", "")
|
||||
BUILTIN(__builtin_ia32_loadhpd, "V2dV2ddC*", "")
|
||||
BUILTIN(__builtin_ia32_loadlpd, "V2dV2ddC*", "")
|
||||
BUILTIN(__builtin_ia32_movmskpd, "iV2d", "")
|
||||
BUILTIN(__builtin_ia32_pmovmskb128, "iV16c", "")
|
||||
BUILTIN(__builtin_ia32_movnti, "vi*i", "")
|
||||
BUILTIN(__builtin_ia32_movntpd, "vd*V2d", "")
|
||||
BUILTIN(__builtin_ia32_movntdq, "vV2LLi*V2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pshufd, "V4iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_pshuflw, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_pshufhw, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_psadbw128, "V2LLiV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_sqrtpd, "V2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_sqrtsd, "V2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_shufpd, "V2dV2dV2di", "")
|
||||
BUILTIN(__builtin_ia32_cvtdq2pd, "V2dV4i", "")
|
||||
BUILTIN(__builtin_ia32_cvtdq2ps, "V4fV4i", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2dq, "V2LLiV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2pi, "V2iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2ps, "V4fV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvttpd2dq, "V4iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvttpd2pi, "V2iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtpi2pd, "V2dV2i", "")
|
||||
BUILTIN(__builtin_ia32_cvtsd2si, "iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvttsd2si, "iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtsd2si64, "LLiV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvttsd2si64, "LLiV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2dq, "V4iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2pd, "V2dV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2dq, "V4iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi2sd, "V2dV2di", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi642sd, "V2dV2dLLi", "")
|
||||
BUILTIN(__builtin_ia32_cvtsd2ss, "V4fV4fV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtss2sd, "V2dV2dV4f", "")
|
||||
BUILTIN(__builtin_ia32_clflush, "vvC*", "")
|
||||
BUILTIN(__builtin_ia32_lfence, "v", "")
|
||||
BUILTIN(__builtin_ia32_mfence, "v", "")
|
||||
BUILTIN(__builtin_ia32_loaddqu, "V16ccC*", "")
|
||||
BUILTIN(__builtin_ia32_storedqu, "vc*V16c", "")
|
||||
BUILTIN(__builtin_ia32_psllwi, "V4sV4si", "")
|
||||
BUILTIN(__builtin_ia32_pslldi, "V2iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_psllqi, "V1LLiV1LLii", "")
|
||||
BUILTIN(__builtin_ia32_psrawi, "V4sV4si", "")
|
||||
BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_psrlwi, "V4sV4si", "")
|
||||
BUILTIN(__builtin_ia32_psrldi, "V2iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_psrlqi, "V1LLiV1LLii", "")
|
||||
BUILTIN(__builtin_ia32_pmuludq, "V1LLiV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "")
|
||||
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_psrlq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_psllw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pslld128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psllq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_psllwi128, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_pslldi128, "V4iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_psllqi128, "V2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_psrlwi128, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_psrldi128, "V4iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_psrlqi128, "V2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_psrawi128, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_psradi128, "V4iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "")
|
||||
BUILTIN(__builtin_ia32_mwait, "vUiUi", "")
|
||||
BUILTIN(__builtin_ia32_movshdup, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_movsldup, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "")
|
||||
BUILTIN(__builtin_ia32_palignr128, "V2LLiV2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLis", "")
|
||||
BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "")
|
||||
BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "")
|
||||
BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v2df, "dV2di", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v2di, "LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v4sf, "fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v4si, "iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v8hi, "UsV8si", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v4hi, "sV4si", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v2si, "iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v8hi, "V8sV8ssi", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v4hi, "V4sV4ssi", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v16qi, "V16cV16cii", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v4si, "V4iV4iii", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v2di, "V2LLiV2LLiLLii", "")
|
||||
BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_loadlv4si, "V4iV2i*", "")
|
||||
BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2di", "")
|
||||
BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_packusdw128, "V8sV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxud128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxuw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pminsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pminsd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pminud128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pminuw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxbd128, "V4iV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxbq128, "V2LLiV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxbw128, "V8sV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxdq128, "V2LLiV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxwd128, "V4iV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxwq128, "V2LLiV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxbd128, "V4iV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxbq128, "V2LLiV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxbw128, "V8sV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxdq128, "V2LLiV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxwd128, "V4iV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxwq128, "V2LLiV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmuldq128, "V2LLiV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmulld128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_roundps, "V4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_roundss, "V4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_roundsd, "V2dV2di", "")
|
||||
BUILTIN(__builtin_ia32_roundpd, "V2dV2di", "")
|
||||
|
||||
|
||||
#undef BUILTIN
|
119
include/clang/Analysis/Analyses/LiveVariables.h
Normal file
119
include/clang/Analysis/Analyses/LiveVariables.h
Normal file
@ -0,0 +1,119 @@
|
||||
//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements Live Variables analysis for source-level CFGs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIVEVARIABLES_H
|
||||
#define LLVM_CLANG_LIVEVARIABLES_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Analysis/Support/BlkExprDeclBitVector.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class DeclRefExpr;
|
||||
class SourceManager;
|
||||
|
||||
struct LiveVariables_ValueTypes {
|
||||
|
||||
struct ObserverTy;
|
||||
|
||||
// We keep dataflow state for declarations and block-level expressions;
|
||||
typedef StmtDeclBitVector_Types::ValTy ValTy;
|
||||
|
||||
// We need to keep track of both declarations and CFGBlock-level expressions,
|
||||
// (so that we don't explore such expressions twice). We also want
|
||||
// to compute liveness information for block-level expressions, since these
|
||||
// act as "temporary" values.
|
||||
|
||||
struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
|
||||
ObserverTy* Observer;
|
||||
ValTy AlwaysLive;
|
||||
|
||||
AnalysisDataTy() : Observer(NULL) {}
|
||||
};
|
||||
|
||||
//===-----------------------------------------------------===//
|
||||
// ObserverTy - Observer for uninitialized values queries.
|
||||
//===-----------------------------------------------------===//
|
||||
|
||||
struct ObserverTy {
|
||||
virtual ~ObserverTy() {}
|
||||
|
||||
/// ObserveStmt - A callback invoked right before invoking the
|
||||
/// liveness transfer function on the given statement.
|
||||
virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD,
|
||||
const ValTy& V) {}
|
||||
|
||||
virtual void ObserverKill(DeclRefExpr* DR) {}
|
||||
};
|
||||
};
|
||||
|
||||
class LiveVariables : public DataflowValues<LiveVariables_ValueTypes,
|
||||
dataflow::backward_analysis_tag> {
|
||||
|
||||
|
||||
public:
|
||||
typedef LiveVariables_ValueTypes::ObserverTy ObserverTy;
|
||||
|
||||
LiveVariables(ASTContext& Ctx, CFG& cfg);
|
||||
|
||||
/// IsLive - Return true if a variable is live at beginning of a
|
||||
/// specified block.
|
||||
bool isLive(const CFGBlock* B, const VarDecl* D) const;
|
||||
|
||||
/// IsLive - Returns true if a variable is live at the beginning of the
|
||||
/// the statement. This query only works if liveness information
|
||||
/// has been recorded at the statement level (see runOnAllBlocks), and
|
||||
/// only returns liveness information for block-level expressions.
|
||||
bool isLive(const Stmt* S, const VarDecl* D) const;
|
||||
|
||||
/// IsLive - Returns true the block-level expression "value" is live
|
||||
/// before the given block-level expression (see runOnAllBlocks).
|
||||
bool isLive(const Stmt* Loc, const Stmt* StmtVal) const;
|
||||
|
||||
/// IsLive - Return true if a variable is live according to the
|
||||
/// provided livness bitvector.
|
||||
bool isLive(const ValTy& V, const VarDecl* D) const;
|
||||
|
||||
/// dumpLiveness - Print to stderr the liveness information encoded
|
||||
/// by a specified bitvector.
|
||||
void dumpLiveness(const ValTy& V, SourceManager& M) const;
|
||||
|
||||
/// dumpBlockLiveness - Print to stderr the liveness information
|
||||
/// associated with each basic block.
|
||||
void dumpBlockLiveness(SourceManager& M) const;
|
||||
|
||||
/// getNumDecls - Return the number of variables (declarations) that
|
||||
/// whose liveness status is being tracked by the dataflow
|
||||
/// analysis.
|
||||
unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); }
|
||||
|
||||
/// IntializeValues - This routine can perform extra initialization, but
|
||||
/// for LiveVariables this does nothing since all that logic is in
|
||||
/// the constructor.
|
||||
void InitializeValues(const CFG& cfg) {}
|
||||
|
||||
void runOnCFG(CFG& cfg);
|
||||
|
||||
/// runOnAllBlocks - Propagate the dataflow values once for each block,
|
||||
/// starting from the current dataflow values. 'recordStmtValues' indicates
|
||||
/// whether the method should store dataflow values per each individual
|
||||
/// block-level expression.
|
||||
void runOnAllBlocks(const CFG& cfg, ObserverTy* Obs,
|
||||
bool recordStmtValues=false);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
74
include/clang/Analysis/Analyses/UninitializedValues.h
Normal file
74
include/clang/Analysis/Analyses/UninitializedValues.h
Normal file
@ -0,0 +1,74 @@
|
||||
//===- UninitializedValues.h - unintialized values analysis ----*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides the interface for the Unintialized Values analysis,
|
||||
// a flow-sensitive analysis that detects when variable values are unintialized.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_UNITVALS_H
|
||||
#define LLVM_CLANG_UNITVALS_H
|
||||
|
||||
#include "clang/Analysis/Support/BlkExprDeclBitVector.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class BlockVarDecl;
|
||||
class Expr;
|
||||
class DeclRefExpr;
|
||||
class VarDecl;
|
||||
|
||||
/// UninitializedValues_ValueTypes - Utility class to wrap type declarations
|
||||
/// for dataflow values and dataflow analysis state for the
|
||||
/// Unitialized Values analysis.
|
||||
class UninitializedValues_ValueTypes {
|
||||
public:
|
||||
|
||||
struct ObserverTy;
|
||||
|
||||
struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
|
||||
AnalysisDataTy() : Observer(NULL), FullUninitTaint(true) {}
|
||||
virtual ~AnalysisDataTy() {};
|
||||
|
||||
ObserverTy* Observer;
|
||||
bool FullUninitTaint;
|
||||
};
|
||||
|
||||
typedef StmtDeclBitVector_Types::ValTy ValTy;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ObserverTy - Observer for querying DeclRefExprs that use an uninitalized
|
||||
// value.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct ObserverTy {
|
||||
virtual ~ObserverTy();
|
||||
virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD,
|
||||
DeclRefExpr* DR, VarDecl* VD) = 0;
|
||||
};
|
||||
};
|
||||
|
||||
/// UninitializedValues - Objects of this class encapsulate dataflow analysis
|
||||
/// information regarding what variable declarations in a function are
|
||||
/// potentially unintialized.
|
||||
class UninitializedValues :
|
||||
public DataflowValues<UninitializedValues_ValueTypes> {
|
||||
public:
|
||||
typedef UninitializedValues_ValueTypes::ObserverTy ObserverTy;
|
||||
|
||||
UninitializedValues(CFG &cfg) { getAnalysisData().setCFG(cfg); }
|
||||
|
||||
/// IntializeValues - Create initial dataflow values and meta data for
|
||||
/// a given CFG. This is intended to be called by the dataflow solver.
|
||||
void InitializeValues(const CFG& cfg);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
27
include/clang/Analysis/AnalysisDiagnostic.h
Normal file
27
include/clang/Analysis/AnalysisDiagnostic.h
Normal file
@ -0,0 +1,27 @@
|
||||
//===--- DiagnosticAnalysis.h - Diagnostics for libanalysis -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_DIAGNOSTICANALYSIS_H
|
||||
#define LLVM_CLANG_DIAGNOSTICANALYSIS_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
|
||||
#define ANALYSISSTART
|
||||
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
|
||||
#undef DIAG
|
||||
NUM_BUILTIN_ANALYSIS_DIAGNOSTICS
|
||||
};
|
||||
} // end namespace diag
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
291
include/clang/Analysis/FlowSensitive/DataflowSolver.h
Normal file
291
include/clang/Analysis/FlowSensitive/DataflowSolver.h
Normal file
@ -0,0 +1,291 @@
|
||||
//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- 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 skeleton code for implementing dataflow analyses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
|
||||
#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "functional" // STL
|
||||
|
||||
namespace clang {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowWorkListTy - Data structure representing the worklist used for
|
||||
/// dataflow algorithms.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class DataflowWorkListTy {
|
||||
typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
|
||||
BlockSet wlist;
|
||||
public:
|
||||
/// enqueue - Add a block to the worklist. Blocks already on the
|
||||
/// worklist are not added a second time.
|
||||
void enqueue(const CFGBlock* B) { wlist.insert(B); }
|
||||
|
||||
/// dequeue - Remove a block from the worklist.
|
||||
const CFGBlock* dequeue() {
|
||||
assert (!wlist.empty());
|
||||
const CFGBlock* B = *wlist.begin();
|
||||
wlist.erase(B);
|
||||
return B;
|
||||
}
|
||||
|
||||
/// isEmpty - Return true if the worklist is empty.
|
||||
bool isEmpty() const { return wlist.empty(); }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BlockItrTraits - Traits classes that allow transparent iteration
|
||||
// over successors/predecessors of a block depending on the direction
|
||||
// of our dataflow analysis.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace dataflow {
|
||||
template<typename Tag> struct ItrTraits {};
|
||||
|
||||
template <> struct ItrTraits<forward_analysis_tag> {
|
||||
typedef CFGBlock::const_pred_iterator PrevBItr;
|
||||
typedef CFGBlock::const_succ_iterator NextBItr;
|
||||
typedef CFGBlock::const_iterator StmtItr;
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); }
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); }
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(Prev, B);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(B, Next);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ItrTraits<backward_analysis_tag> {
|
||||
typedef CFGBlock::const_succ_iterator PrevBItr;
|
||||
typedef CFGBlock::const_pred_iterator NextBItr;
|
||||
typedef CFGBlock::const_reverse_iterator StmtItr;
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); }
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(B, Prev);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(Next, B);
|
||||
}
|
||||
};
|
||||
} // end namespace dataflow
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowSolverTy - Generic dataflow solver.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename _DFValuesTy, // Usually a subclass of DataflowValues
|
||||
typename _TransferFuncsTy,
|
||||
typename _MergeOperatorTy,
|
||||
typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> >
|
||||
class DataflowSolver {
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// Type declarations.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
public:
|
||||
typedef _DFValuesTy DFValuesTy;
|
||||
typedef _TransferFuncsTy TransferFuncsTy;
|
||||
typedef _MergeOperatorTy MergeOperatorTy;
|
||||
|
||||
typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag;
|
||||
typedef typename _DFValuesTy::ValTy ValTy;
|
||||
typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy;
|
||||
typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy;
|
||||
|
||||
typedef dataflow::ItrTraits<AnalysisDirTag> ItrTraits;
|
||||
typedef typename ItrTraits::NextBItr NextBItr;
|
||||
typedef typename ItrTraits::PrevBItr PrevBItr;
|
||||
typedef typename ItrTraits::StmtItr StmtItr;
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// External interface: constructing and running the solver.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
public:
|
||||
DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {}
|
||||
~DataflowSolver() {}
|
||||
|
||||
/// runOnCFG - Computes dataflow values for all blocks in a CFG.
|
||||
void runOnCFG(CFG& cfg, bool recordStmtValues = false) {
|
||||
// Set initial dataflow values and boundary conditions.
|
||||
D.InitializeValues(cfg);
|
||||
// Solve the dataflow equations. This will populate D.EdgeDataMap
|
||||
// with dataflow values.
|
||||
SolveDataflowEquations(cfg, recordStmtValues);
|
||||
}
|
||||
|
||||
/// runOnBlock - Computes dataflow values for a given block. This
|
||||
/// should usually be invoked only after previously computing
|
||||
/// dataflow values using runOnCFG, as runOnBlock is intended to
|
||||
/// only be used for querying the dataflow values within a block
|
||||
/// with and Observer object.
|
||||
void runOnBlock(const CFGBlock* B, bool recordStmtValues) {
|
||||
BlockDataMapTy& M = D.getBlockDataMap();
|
||||
typename BlockDataMapTy::iterator I = M.find(B);
|
||||
|
||||
if (I != M.end()) {
|
||||
TF.getVal().copyValues(I->second);
|
||||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
}
|
||||
|
||||
void runOnBlock(const CFGBlock& B, bool recordStmtValues) {
|
||||
runOnBlock(&B, recordStmtValues);
|
||||
}
|
||||
void runOnBlock(CFG::iterator& I, bool recordStmtValues) {
|
||||
runOnBlock(*I, recordStmtValues);
|
||||
}
|
||||
void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) {
|
||||
runOnBlock(*I, recordStmtValues);
|
||||
}
|
||||
|
||||
void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) {
|
||||
for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
runOnBlock(I, recordStmtValues);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// Internal solver logic.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
private:
|
||||
|
||||
/// SolveDataflowEquations - Perform the actual worklist algorithm
|
||||
/// to compute dataflow values.
|
||||
void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
|
||||
// Enqueue all blocks to ensure the dataflow values are computed
|
||||
// for every block. Not all blocks are guaranteed to reach the exit block.
|
||||
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
WorkList.enqueue(&*I);
|
||||
|
||||
while (!WorkList.isEmpty()) {
|
||||
const CFGBlock* B = WorkList.dequeue();
|
||||
ProcessMerge(cfg,B);
|
||||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
UpdateEdges(cfg,B,TF.getVal());
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
|
||||
ValTy& V = TF.getVal();
|
||||
TF.SetTopValue(V);
|
||||
|
||||
// Merge dataflow values from all predecessors of this block.
|
||||
MergeOperatorTy Merge;
|
||||
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
bool firstMerge = true;
|
||||
|
||||
for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){
|
||||
|
||||
typename EdgeDataMapTy::iterator EI =
|
||||
M.find(ItrTraits::PrevEdge(B, *I));
|
||||
|
||||
if (EI != M.end()) {
|
||||
if (firstMerge) {
|
||||
firstMerge = false;
|
||||
V.copyValues(EI->second);
|
||||
}
|
||||
else Merge(V,EI->second);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the data for the block.
|
||||
D.getBlockDataMap()[B].copyValues(V);
|
||||
}
|
||||
|
||||
/// ProcessBlock - Process the transfer functions for a given block.
|
||||
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.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
}
|
||||
|
||||
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
|
||||
dataflow::backward_analysis_tag) {
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
|
||||
ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
|
||||
void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) {
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
}
|
||||
|
||||
/// UpdateEdges - After processing the transfer functions for a
|
||||
/// block, update the dataflow value associated with the block's
|
||||
/// outgoing/incoming edges (depending on whether we do a
|
||||
// forward/backward analysis respectively)
|
||||
void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) {
|
||||
for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
|
||||
UpdateEdgeValue(ItrTraits::NextEdge(B, *I),V,*I);
|
||||
}
|
||||
|
||||
/// UpdateEdgeValue - Update the value associated with a given edge.
|
||||
void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) {
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
typename EdgeDataMapTy::iterator I = M.find(E);
|
||||
|
||||
if (I == M.end()) { // First computed value for this edge?
|
||||
M[E].copyValues(V);
|
||||
WorkList.enqueue(TargetBlock);
|
||||
}
|
||||
else if (!_Equal()(V,I->second)) {
|
||||
I->second.copyValues(V);
|
||||
WorkList.enqueue(TargetBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DFValuesTy& D;
|
||||
DataflowWorkListTy WorkList;
|
||||
TransferFuncsTy TF;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
172
include/clang/Analysis/FlowSensitive/DataflowValues.h
Normal file
172
include/clang/Analysis/FlowSensitive/DataflowValues.h
Normal file
@ -0,0 +1,172 @@
|
||||
//===--- DataflowValues.h - Data structure for dataflow 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 a skeleton data structure for encapsulating the dataflow
|
||||
// values for a CFG. Typically this is subclassed to provide methods for
|
||||
// computing these values from a CFG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
|
||||
#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// Dataflow Directional Tag Classes. These are used for tag dispatching
|
||||
/// within the dataflow solver/transfer functions to determine what direction
|
||||
/// a dataflow analysis flows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
struct forward_analysis_tag {};
|
||||
struct backward_analysis_tag {};
|
||||
} // end namespace dataflow
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowValues. Container class to store dataflow values for a CFG.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename ValueTypes,
|
||||
typename _AnalysisDirTag = dataflow::forward_analysis_tag >
|
||||
class DataflowValues {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type declarations.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
typedef typename ValueTypes::ValTy ValTy;
|
||||
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
|
||||
typedef _AnalysisDirTag AnalysisDirTag;
|
||||
typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
|
||||
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
|
||||
typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Predicates.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
/// isForwardAnalysis - Returns true if the dataflow values are computed
|
||||
/// from a forward analysis.
|
||||
bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); }
|
||||
|
||||
/// isBackwardAnalysis - Returns true if the dataflow values are computed
|
||||
/// from a backward analysis.
|
||||
bool isBackwardAnalysis() { return !isForwardAnalysis(); }
|
||||
|
||||
private:
|
||||
bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; }
|
||||
bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Initialization and accessors methods.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
DataflowValues() : StmtDataMap(NULL) {}
|
||||
~DataflowValues() { delete StmtDataMap; }
|
||||
|
||||
/// InitializeValues - Invoked by the solver to initialize state needed for
|
||||
/// dataflow analysis. This method is usually specialized by subclasses.
|
||||
void InitializeValues(const CFG& cfg) {};
|
||||
|
||||
|
||||
/// getEdgeData - Retrieves the dataflow values associated with a
|
||||
/// CFG edge.
|
||||
ValTy& getEdgeData(const BlockEdge& E) {
|
||||
typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E);
|
||||
assert (I != EdgeDataMap.end() && "No data associated with Edge.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getEdgeData(const BlockEdge& E) const {
|
||||
return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
|
||||
}
|
||||
|
||||
/// getBlockData - Retrieves the dataflow values associated with a
|
||||
/// specified CFGBlock. If the dataflow analysis is a forward analysis,
|
||||
/// this data is associated with the END of the block. If the analysis
|
||||
/// is a backwards analysis, it is associated with the ENTRY of the block.
|
||||
ValTy& getBlockData(const CFGBlock* B) {
|
||||
typename BlockDataMapTy::iterator I = BlockDataMap.find(B);
|
||||
assert (I != BlockDataMap.end() && "No data associated with block.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getBlockData(const CFGBlock* B) const {
|
||||
return const_cast<DataflowValues*>(this)->getBlockData(B);
|
||||
}
|
||||
|
||||
/// getStmtData - Retrieves the dataflow values associated with a
|
||||
/// specified Stmt. If the dataflow analysis is a forward analysis,
|
||||
/// this data corresponds to the point immediately before a Stmt.
|
||||
/// If the analysis is a backwards analysis, it is associated with
|
||||
/// the point after a Stmt. This data is only computed for block-level
|
||||
/// expressions, and only when requested when the analysis is executed.
|
||||
ValTy& getStmtData(const Stmt* S) {
|
||||
assert (StmtDataMap && "Dataflow values were not computed for statements.");
|
||||
typename StmtDataMapTy::iterator I = StmtDataMap->find(S);
|
||||
assert (I != StmtDataMap->end() && "No data associated with statement.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getStmtData(const Stmt* S) const {
|
||||
return const_cast<DataflowValues*>(this)->getStmtData(S);
|
||||
}
|
||||
|
||||
/// getEdgeDataMap - Retrieves the internal map between CFG edges and
|
||||
/// dataflow values. Usually used by a dataflow solver to compute
|
||||
/// values for blocks.
|
||||
EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; }
|
||||
const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; }
|
||||
|
||||
/// getBlockDataMap - Retrieves the internal map between CFGBlocks and
|
||||
/// dataflow values. If the dataflow analysis operates in the forward
|
||||
/// direction, the values correspond to the dataflow values at the start
|
||||
/// of the block. Otherwise, for a backward analysis, the values correpsond
|
||||
/// to the dataflow values at the end of the block.
|
||||
BlockDataMapTy& getBlockDataMap() { return BlockDataMap; }
|
||||
const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; }
|
||||
|
||||
/// getStmtDataMap - Retrieves the internal map between Stmts and
|
||||
/// dataflow values.
|
||||
StmtDataMapTy& getStmtDataMap() {
|
||||
if (!StmtDataMap) StmtDataMap = new StmtDataMapTy();
|
||||
return *StmtDataMap;
|
||||
}
|
||||
|
||||
const StmtDataMapTy& getStmtDataMap() const {
|
||||
return const_cast<DataflowValues*>(this)->getStmtDataMap();
|
||||
}
|
||||
|
||||
/// getAnalysisData - Retrieves the meta data associated with a
|
||||
/// dataflow analysis for analyzing a particular CFG.
|
||||
/// This is typically consumed by transfer function code (via the solver).
|
||||
/// This can also be used by subclasses to interpret the dataflow values.
|
||||
AnalysisDataTy& getAnalysisData() { return AnalysisData; }
|
||||
const AnalysisDataTy& getAnalysisData() const { return AnalysisData; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
protected:
|
||||
EdgeDataMapTy EdgeDataMap;
|
||||
BlockDataMapTy BlockDataMap;
|
||||
StmtDataMapTy* StmtDataMap;
|
||||
AnalysisDataTy AnalysisData;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
54
include/clang/Analysis/LocalCheckers.h
Normal file
54
include/clang/Analysis/LocalCheckers.h
Normal file
@ -0,0 +1,54 @@
|
||||
//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive Checkers -*- 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 interface to call a set of intra-procedural (local)
|
||||
// checkers that use flow/path-sensitive analyses to find bugs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H
|
||||
#define LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CFG;
|
||||
class Decl;
|
||||
class Diagnostic;
|
||||
class ASTContext;
|
||||
class PathDiagnosticClient;
|
||||
class GRTransferFuncs;
|
||||
class BugType;
|
||||
class LangOptions;
|
||||
class ParentMap;
|
||||
class LiveVariables;
|
||||
class BugReporter;
|
||||
class ObjCImplementationDecl;
|
||||
class LangOptions;
|
||||
class GRExprEngine;
|
||||
|
||||
void CheckDeadStores(LiveVariables& L, BugReporter& BR);
|
||||
|
||||
void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
|
||||
bool FullUninitTaint=false);
|
||||
|
||||
GRTransferFuncs* MakeGRSimpleValsTF();
|
||||
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
|
||||
const LangOptions& lopts);
|
||||
|
||||
void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L,
|
||||
BugReporter& BR);
|
||||
|
||||
void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR);
|
||||
void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR);
|
||||
|
||||
void RegisterAppleChecks(GRExprEngine& Eng);
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
487
include/clang/Analysis/PathDiagnostic.h
Normal file
487
include/clang/Analysis/PathDiagnostic.h
Normal file
@ -0,0 +1,487 @@
|
||||
//===--- PathDiagnostic.h - Path-Specific Diagnostic 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 PathDiagnostic-related interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
|
||||
#define LLVM_CLANG_PATH_DIAGNOSTIC_H
|
||||
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// High-level interface for handlers of path-sensitive diagnostics.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class PathDiagnostic;
|
||||
class Stmt;
|
||||
class Decl;
|
||||
class Preprocessor;
|
||||
|
||||
class PathDiagnosticClient : public DiagnosticClient {
|
||||
public:
|
||||
PathDiagnosticClient() {}
|
||||
virtual ~PathDiagnosticClient() {}
|
||||
|
||||
virtual void SetPreprocessor(Preprocessor *PP) {}
|
||||
|
||||
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
||||
const DiagnosticInfo &Info);
|
||||
|
||||
virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0;
|
||||
|
||||
enum PathGenerationScheme { Minimal, Extensive };
|
||||
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
|
||||
virtual bool supportsLogicalOpControlFlow() const { return false; }
|
||||
virtual bool supportsAllBlockEdges() const { return false; }
|
||||
virtual bool useVerboseDescription() const { return true; }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Path-sensitive diagnostics.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class PathDiagnosticRange : public SourceRange {
|
||||
public:
|
||||
const bool isPoint;
|
||||
|
||||
PathDiagnosticRange(const SourceRange &R, bool isP = false)
|
||||
: SourceRange(R), isPoint(isP) {}
|
||||
};
|
||||
|
||||
class PathDiagnosticLocation {
|
||||
private:
|
||||
enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
|
||||
SourceRange R;
|
||||
const Stmt *S;
|
||||
const Decl *D;
|
||||
const SourceManager *SM;
|
||||
public:
|
||||
PathDiagnosticLocation()
|
||||
: K(SingleLocK), S(0), D(0), SM(0) {}
|
||||
|
||||
PathDiagnosticLocation(FullSourceLoc L)
|
||||
: K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {}
|
||||
|
||||
PathDiagnosticLocation(const Stmt *s, const SourceManager &sm)
|
||||
: K(StmtK), S(s), D(0), SM(&sm) {}
|
||||
|
||||
PathDiagnosticLocation(SourceRange r, const SourceManager &sm)
|
||||
: K(RangeK), R(r), S(0), D(0), SM(&sm) {}
|
||||
|
||||
PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
|
||||
: K(DeclK), S(0), D(d), SM(&sm) {}
|
||||
|
||||
bool operator==(const PathDiagnosticLocation &X) const {
|
||||
return K == X.K && R == X.R && S == X.S && D == X.D;
|
||||
}
|
||||
|
||||
bool operator!=(const PathDiagnosticLocation &X) const {
|
||||
return K != X.K || R != X.R || S != X.S || D != X.D;;
|
||||
}
|
||||
|
||||
PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) {
|
||||
K = X.K;
|
||||
R = X.R;
|
||||
S = X.S;
|
||||
D = X.D;
|
||||
SM = X.SM;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return SM != 0;
|
||||
}
|
||||
|
||||
const SourceManager& getSourceManager() const { assert(isValid());return *SM;}
|
||||
|
||||
FullSourceLoc asLocation() const;
|
||||
PathDiagnosticRange asRange() const;
|
||||
const Stmt *asStmt() const { assert(isValid()); return S; }
|
||||
const Decl *asDecl() const { assert(isValid()); return D; }
|
||||
|
||||
bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
|
||||
|
||||
void invalidate() {
|
||||
*this = PathDiagnosticLocation();
|
||||
}
|
||||
|
||||
void flatten();
|
||||
|
||||
const SourceManager& getManager() const { assert(isValid()); return *SM; }
|
||||
};
|
||||
|
||||
class PathDiagnosticLocationPair {
|
||||
private:
|
||||
PathDiagnosticLocation Start, End;
|
||||
public:
|
||||
PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
|
||||
const PathDiagnosticLocation &end)
|
||||
: Start(start), End(end) {}
|
||||
|
||||
const PathDiagnosticLocation &getStart() const { return Start; }
|
||||
const PathDiagnosticLocation &getEnd() const { return End; }
|
||||
|
||||
void flatten() {
|
||||
Start.flatten();
|
||||
End.flatten();
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Path "pieces" for path-sensitive diagnostics.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class PathDiagnosticPiece {
|
||||
public:
|
||||
enum Kind { ControlFlow, Event, Macro };
|
||||
enum DisplayHint { Above, Below };
|
||||
|
||||
private:
|
||||
const std::string str;
|
||||
std::vector<CodeModificationHint> CodeModificationHints;
|
||||
const Kind kind;
|
||||
const DisplayHint Hint;
|
||||
std::vector<SourceRange> ranges;
|
||||
|
||||
// Do not implement:
|
||||
PathDiagnosticPiece();
|
||||
PathDiagnosticPiece(const PathDiagnosticPiece &P);
|
||||
PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
|
||||
|
||||
protected:
|
||||
PathDiagnosticPiece(const std::string& s, Kind k, DisplayHint hint = Below);
|
||||
|
||||
PathDiagnosticPiece(const char* s, Kind k, DisplayHint hint = Below);
|
||||
|
||||
PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
|
||||
|
||||
public:
|
||||
virtual ~PathDiagnosticPiece();
|
||||
|
||||
const std::string& getString() const { return str; }
|
||||
|
||||
/// getDisplayHint - Return a hint indicating where the diagnostic should
|
||||
/// be displayed by the PathDiagnosticClient.
|
||||
DisplayHint getDisplayHint() const { return Hint; }
|
||||
|
||||
virtual PathDiagnosticLocation getLocation() const = 0;
|
||||
virtual void flattenLocations() = 0;
|
||||
|
||||
Kind getKind() const { return kind; }
|
||||
|
||||
void addRange(SourceRange R) { ranges.push_back(R); }
|
||||
|
||||
void addRange(SourceLocation B, SourceLocation E) {
|
||||
ranges.push_back(SourceRange(B,E));
|
||||
}
|
||||
|
||||
void addCodeModificationHint(const CodeModificationHint& Hint) {
|
||||
CodeModificationHints.push_back(Hint);
|
||||
}
|
||||
|
||||
typedef const SourceRange* range_iterator;
|
||||
|
||||
range_iterator ranges_begin() const {
|
||||
return ranges.empty() ? NULL : &ranges[0];
|
||||
}
|
||||
|
||||
range_iterator ranges_end() const {
|
||||
return ranges_begin() + ranges.size();
|
||||
}
|
||||
|
||||
typedef const CodeModificationHint *code_modifications_iterator;
|
||||
|
||||
code_modifications_iterator code_modifications_begin() const {
|
||||
return CodeModificationHints.empty()? 0 : &CodeModificationHints[0];
|
||||
}
|
||||
|
||||
code_modifications_iterator code_modifications_end() const {
|
||||
return CodeModificationHints.empty()? 0
|
||||
: &CodeModificationHints[0] + CodeModificationHints.size();
|
||||
}
|
||||
|
||||
static inline bool classof(const PathDiagnosticPiece* P) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
|
||||
private:
|
||||
PathDiagnosticLocation Pos;
|
||||
public:
|
||||
PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
|
||||
const std::string& s,
|
||||
PathDiagnosticPiece::Kind k,
|
||||
bool addPosRange = true)
|
||||
: PathDiagnosticPiece(s, k), Pos(pos) {
|
||||
assert(Pos.asLocation().isValid() &&
|
||||
"PathDiagnosticSpotPiece's must have a valid location.");
|
||||
if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
|
||||
}
|
||||
|
||||
PathDiagnosticLocation getLocation() const { return Pos; }
|
||||
virtual void flattenLocations() { Pos.flatten(); }
|
||||
};
|
||||
|
||||
class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
|
||||
|
||||
public:
|
||||
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
|
||||
const std::string& s, bool addPosRange = true)
|
||||
: PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
|
||||
|
||||
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, const char* s,
|
||||
bool addPosRange = true)
|
||||
: PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
|
||||
|
||||
~PathDiagnosticEventPiece();
|
||||
|
||||
static inline bool classof(const PathDiagnosticPiece* P) {
|
||||
return P->getKind() == Event;
|
||||
}
|
||||
};
|
||||
|
||||
class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
|
||||
std::vector<PathDiagnosticLocationPair> LPairs;
|
||||
public:
|
||||
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
|
||||
const PathDiagnosticLocation &endPos,
|
||||
const std::string& s)
|
||||
: PathDiagnosticPiece(s, ControlFlow) {
|
||||
LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
|
||||
}
|
||||
|
||||
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
|
||||
const PathDiagnosticLocation &endPos,
|
||||
const char* s)
|
||||
: PathDiagnosticPiece(s, ControlFlow) {
|
||||
LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
|
||||
}
|
||||
|
||||
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
|
||||
const PathDiagnosticLocation &endPos)
|
||||
: PathDiagnosticPiece(ControlFlow) {
|
||||
LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
|
||||
}
|
||||
|
||||
~PathDiagnosticControlFlowPiece();
|
||||
|
||||
PathDiagnosticLocation getStartLocation() const {
|
||||
assert(!LPairs.empty() &&
|
||||
"PathDiagnosticControlFlowPiece needs at least one location.");
|
||||
return LPairs[0].getStart();
|
||||
}
|
||||
|
||||
PathDiagnosticLocation getEndLocation() const {
|
||||
assert(!LPairs.empty() &&
|
||||
"PathDiagnosticControlFlowPiece needs at least one location.");
|
||||
return LPairs[0].getEnd();
|
||||
}
|
||||
|
||||
void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
|
||||
|
||||
virtual PathDiagnosticLocation getLocation() const {
|
||||
return getStartLocation();
|
||||
}
|
||||
|
||||
typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
|
||||
iterator begin() { return LPairs.begin(); }
|
||||
iterator end() { return LPairs.end(); }
|
||||
|
||||
virtual void flattenLocations() {
|
||||
for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
|
||||
}
|
||||
|
||||
typedef std::vector<PathDiagnosticLocationPair>::const_iterator
|
||||
const_iterator;
|
||||
const_iterator begin() const { return LPairs.begin(); }
|
||||
const_iterator end() const { return LPairs.end(); }
|
||||
|
||||
static inline bool classof(const PathDiagnosticPiece* P) {
|
||||
return P->getKind() == ControlFlow;
|
||||
}
|
||||
};
|
||||
|
||||
class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
|
||||
std::vector<PathDiagnosticPiece*> SubPieces;
|
||||
public:
|
||||
PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
|
||||
: PathDiagnosticSpotPiece(pos, "", Macro) {}
|
||||
|
||||
~PathDiagnosticMacroPiece();
|
||||
|
||||
bool containsEvent() const;
|
||||
|
||||
void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); }
|
||||
|
||||
typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
|
||||
iterator begin() { return SubPieces.begin(); }
|
||||
iterator end() { return SubPieces.end(); }
|
||||
|
||||
virtual void flattenLocations() {
|
||||
PathDiagnosticSpotPiece::flattenLocations();
|
||||
for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations();
|
||||
}
|
||||
|
||||
typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator;
|
||||
const_iterator begin() const { return SubPieces.begin(); }
|
||||
const_iterator end() const { return SubPieces.end(); }
|
||||
|
||||
static inline bool classof(const PathDiagnosticPiece* P) {
|
||||
return P->getKind() == Macro;
|
||||
}
|
||||
};
|
||||
|
||||
/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
|
||||
/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
|
||||
/// each which represent the pieces of the path.
|
||||
class PathDiagnostic {
|
||||
std::deque<PathDiagnosticPiece*> path;
|
||||
unsigned Size;
|
||||
std::string BugType;
|
||||
std::string Desc;
|
||||
std::string Category;
|
||||
std::deque<std::string> OtherDesc;
|
||||
|
||||
public:
|
||||
PathDiagnostic();
|
||||
|
||||
PathDiagnostic(const char* bugtype, const char* desc, const char* category);
|
||||
|
||||
PathDiagnostic(const std::string& bugtype, const std::string& desc,
|
||||
const std::string& category);
|
||||
|
||||
~PathDiagnostic();
|
||||
|
||||
const std::string& getDescription() const { return Desc; }
|
||||
const std::string& getBugType() const { return BugType; }
|
||||
const std::string& getCategory() const { return Category; }
|
||||
|
||||
typedef std::deque<std::string>::const_iterator meta_iterator;
|
||||
meta_iterator meta_begin() const { return OtherDesc.begin(); }
|
||||
meta_iterator meta_end() const { return OtherDesc.end(); }
|
||||
void addMeta(const std::string& s) { OtherDesc.push_back(s); }
|
||||
void addMeta(const char* s) { OtherDesc.push_back(s); }
|
||||
|
||||
PathDiagnosticLocation getLocation() const {
|
||||
assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
|
||||
return rbegin()->getLocation();
|
||||
}
|
||||
|
||||
void push_front(PathDiagnosticPiece* piece) {
|
||||
path.push_front(piece);
|
||||
++Size;
|
||||
}
|
||||
|
||||
void push_back(PathDiagnosticPiece* piece) {
|
||||
path.push_back(piece);
|
||||
++Size;
|
||||
}
|
||||
|
||||
PathDiagnosticPiece* back() {
|
||||
return path.back();
|
||||
}
|
||||
|
||||
const PathDiagnosticPiece* back() const {
|
||||
return path.back();
|
||||
}
|
||||
|
||||
unsigned size() const { return Size; }
|
||||
bool empty() const { return Size == 0; }
|
||||
|
||||
void resetPath(bool deletePieces = true);
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy;
|
||||
|
||||
typedef PathDiagnosticPiece value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
ImplTy I;
|
||||
|
||||
public:
|
||||
iterator(const ImplTy& i) : I(i) {}
|
||||
|
||||
bool operator==(const iterator& X) const { return I == X.I; }
|
||||
bool operator!=(const iterator& X) const { return I != X.I; }
|
||||
|
||||
PathDiagnosticPiece& operator*() const { return **I; }
|
||||
PathDiagnosticPiece* operator->() const { return *I; }
|
||||
|
||||
iterator& operator++() { ++I; return *this; }
|
||||
iterator& operator--() { --I; return *this; }
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
public:
|
||||
typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy;
|
||||
|
||||
typedef const PathDiagnosticPiece value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
ImplTy I;
|
||||
|
||||
public:
|
||||
const_iterator(const ImplTy& i) : I(i) {}
|
||||
|
||||
bool operator==(const const_iterator& X) const { return I == X.I; }
|
||||
bool operator!=(const const_iterator& X) const { return I != X.I; }
|
||||
|
||||
reference operator*() const { return **I; }
|
||||
pointer operator->() const { return *I; }
|
||||
|
||||
const_iterator& operator++() { ++I; return *this; }
|
||||
const_iterator& operator--() { --I; return *this; }
|
||||
};
|
||||
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
// forward iterator creation methods.
|
||||
|
||||
iterator begin() { return path.begin(); }
|
||||
iterator end() { return path.end(); }
|
||||
|
||||
const_iterator begin() const { return path.begin(); }
|
||||
const_iterator end() const { return path.end(); }
|
||||
|
||||
// reverse iterator creation methods.
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
|
||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
|
||||
|
||||
void flattenLocations() {
|
||||
for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} //end clang namespace
|
||||
#endif
|
163
include/clang/Analysis/PathSensitive/BasicValueFactory.h
Normal file
163
include/clang/Analysis/PathSensitive/BasicValueFactory.h
Normal file
@ -0,0 +1,163 @@
|
||||
//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- 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 BasicValueFactory, a class that manages the lifetime
|
||||
// of APSInt objects and symbolic constraints used by GRExprEngine
|
||||
// and related classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
|
||||
#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
|
||||
|
||||
#include "clang/Analysis/PathSensitive/SymbolManager.h"
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/ImmutableList.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CompoundValData : public llvm::FoldingSetNode {
|
||||
QualType T;
|
||||
llvm::ImmutableList<SVal> L;
|
||||
|
||||
public:
|
||||
CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
|
||||
: T(t), L(l) {}
|
||||
|
||||
typedef llvm::ImmutableList<SVal>::iterator iterator;
|
||||
iterator begin() const { return L.begin(); }
|
||||
iterator end() const { return L.end(); }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, QualType T,
|
||||
llvm::ImmutableList<SVal> L);
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); }
|
||||
};
|
||||
|
||||
class BasicValueFactory {
|
||||
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
|
||||
APSIntSetTy;
|
||||
|
||||
ASTContext& Ctx;
|
||||
llvm::BumpPtrAllocator& BPAlloc;
|
||||
|
||||
APSIntSetTy APSIntSet;
|
||||
void* PersistentSVals;
|
||||
void* PersistentSValPairs;
|
||||
|
||||
llvm::ImmutableList<SVal>::Factory SValListFactory;
|
||||
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
|
||||
|
||||
public:
|
||||
BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
|
||||
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
|
||||
SValListFactory(Alloc) {}
|
||||
|
||||
~BasicValueFactory();
|
||||
|
||||
ASTContext& getContext() const { return Ctx; }
|
||||
|
||||
const llvm::APSInt& getValue(const llvm::APSInt& X);
|
||||
const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
|
||||
const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
|
||||
const llvm::APSInt& getValue(uint64_t X, QualType T);
|
||||
|
||||
/// Convert - Create a new persistent APSInt with the same value as 'From'
|
||||
/// but with the bitwidth and signedness of 'To'.
|
||||
const llvm::APSInt& Convert(const llvm::APSInt& To,
|
||||
const llvm::APSInt& From) {
|
||||
|
||||
if (To.isUnsigned() == From.isUnsigned() &&
|
||||
To.getBitWidth() == From.getBitWidth())
|
||||
return From;
|
||||
|
||||
return getValue(From.getSExtValue(),
|
||||
To.getBitWidth(),
|
||||
To.isUnsigned());
|
||||
}
|
||||
|
||||
const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
|
||||
QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy;
|
||||
return getValue(X, T);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) {
|
||||
return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned()));
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) {
|
||||
return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned()));
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getMaxValue(QualType T) {
|
||||
assert(T->isIntegerType() || Loc::IsLocType(T));
|
||||
bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
|
||||
return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned));
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getMinValue(QualType T) {
|
||||
assert(T->isIntegerType() || Loc::IsLocType(T));
|
||||
bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
|
||||
return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned));
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& Add1(const llvm::APSInt& V) {
|
||||
llvm::APSInt X = V;
|
||||
++X;
|
||||
return getValue(X);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& Sub1(const llvm::APSInt& V) {
|
||||
llvm::APSInt X = V;
|
||||
--X;
|
||||
return getValue(X);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
|
||||
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getTruthValue(bool b, QualType T) {
|
||||
return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getTruthValue(bool b) {
|
||||
return getTruthValue(b, Ctx.IntTy);
|
||||
}
|
||||
|
||||
const CompoundValData* getCompoundValData(QualType T,
|
||||
llvm::ImmutableList<SVal> Vals);
|
||||
|
||||
llvm::ImmutableList<SVal> getEmptySValList() {
|
||||
return SValListFactory.GetEmptyList();
|
||||
}
|
||||
|
||||
llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
|
||||
return SValListFactory.Add(X, L);
|
||||
}
|
||||
|
||||
const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op,
|
||||
const llvm::APSInt& V1,
|
||||
const llvm::APSInt& V2);
|
||||
|
||||
const std::pair<SVal, uintptr_t>&
|
||||
getPersistentSValWithData(const SVal& V, uintptr_t Data);
|
||||
|
||||
const std::pair<SVal, SVal>&
|
||||
getPersistentSValPair(const SVal& V1, const SVal& V2);
|
||||
|
||||
const SVal* getPersistentSVal(SVal X);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
466
include/clang/Analysis/PathSensitive/BugReporter.h
Normal file
466
include/clang/Analysis/PathSensitive/BugReporter.h
Normal file
@ -0,0 +1,466 @@
|
||||
//===--- BugReporter.h - Generate PathDiagnostics --------------*- 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 BugReporter, a utility class for generating
|
||||
// PathDiagnostics for analyses based on GRState.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER
|
||||
#define LLVM_CLANG_ANALYSIS_BUGREPORTER
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/ImmutableSet.h"
|
||||
#include <list>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PathDiagnostic;
|
||||
class PathDiagnosticPiece;
|
||||
class PathDiagnosticClient;
|
||||
class ASTContext;
|
||||
class Diagnostic;
|
||||
class BugReporter;
|
||||
class BugReporterContext;
|
||||
class GRExprEngine;
|
||||
class GRState;
|
||||
class Stmt;
|
||||
class BugType;
|
||||
class ParentMap;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Interface for individual bug reports.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class BugReporterVisitor {
|
||||
public:
|
||||
virtual ~BugReporterVisitor();
|
||||
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
|
||||
const ExplodedNode<GRState>* PrevN,
|
||||
BugReporterContext& BRC) = 0;
|
||||
|
||||
virtual bool isOwnedByReporterContext() { return true; }
|
||||
};
|
||||
|
||||
// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
|
||||
class BugReport : public BugReporterVisitor {
|
||||
protected:
|
||||
BugType& BT;
|
||||
std::string ShortDescription;
|
||||
std::string Description;
|
||||
const ExplodedNode<GRState> *EndNode;
|
||||
SourceRange R;
|
||||
|
||||
protected:
|
||||
friend class BugReporter;
|
||||
friend class BugReportEquivClass;
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& hash) const {
|
||||
hash.AddInteger(getLocation().getRawEncoding());
|
||||
}
|
||||
|
||||
public:
|
||||
class NodeResolver {
|
||||
public:
|
||||
virtual ~NodeResolver() {}
|
||||
virtual const ExplodedNode<GRState>*
|
||||
getOriginalNode(const ExplodedNode<GRState>* N) = 0;
|
||||
};
|
||||
|
||||
BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n)
|
||||
: BT(bt), Description(desc), EndNode(n) {}
|
||||
|
||||
BugReport(BugType& bt, const char* shortDesc, const char* desc,
|
||||
const ExplodedNode<GRState> *n)
|
||||
: BT(bt), ShortDescription(shortDesc), Description(desc), EndNode(n) {}
|
||||
|
||||
virtual ~BugReport();
|
||||
|
||||
virtual bool isOwnedByReporterContext() { return false; }
|
||||
|
||||
const BugType& getBugType() const { return BT; }
|
||||
BugType& getBugType() { return BT; }
|
||||
|
||||
// FIXME: Perhaps this should be moved into a subclass?
|
||||
const ExplodedNode<GRState>* getEndNode() const { return EndNode; }
|
||||
|
||||
// FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint
|
||||
// object.
|
||||
// FIXME: If we do need it, we can probably just make it private to
|
||||
// BugReporter.
|
||||
Stmt* getStmt(BugReporter& BR) const;
|
||||
|
||||
const std::string& getDescription() const { return Description; }
|
||||
|
||||
const std::string& getShortDescription() const {
|
||||
return ShortDescription.empty() ? Description : ShortDescription;
|
||||
}
|
||||
|
||||
// FIXME: Is this needed?
|
||||
virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
|
||||
return std::make_pair((const char**)0,(const char**)0);
|
||||
}
|
||||
|
||||
// FIXME: Perhaps move this into a subclass.
|
||||
virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
|
||||
const ExplodedNode<GRState>* N);
|
||||
|
||||
/// getLocation - Return the "definitive" location of the reported bug.
|
||||
/// While a bug can span an entire path, usually there is a specific
|
||||
/// location that can be used to identify where the key issue occured.
|
||||
/// This location is used by clients rendering diagnostics.
|
||||
virtual SourceLocation getLocation() const;
|
||||
|
||||
/// getRanges - Returns the source ranges associated with this bug.
|
||||
virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
|
||||
const SourceRange*& end);
|
||||
|
||||
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
|
||||
const ExplodedNode<GRState>* PrevN,
|
||||
BugReporterContext& BR);
|
||||
|
||||
virtual void registerInitialVisitors(BugReporterContext& BRC,
|
||||
const ExplodedNode<GRState>* N) {}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BugTypes (collections of related reports).
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class BugReportEquivClass : public llvm::FoldingSetNode {
|
||||
// List of *owned* BugReport objects.
|
||||
std::list<BugReport*> Reports;
|
||||
|
||||
friend class BugReporter;
|
||||
void AddReport(BugReport* R) { Reports.push_back(R); }
|
||||
public:
|
||||
BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
|
||||
~BugReportEquivClass();
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
assert(!Reports.empty());
|
||||
(*Reports.begin())->Profile(ID);
|
||||
}
|
||||
|
||||
class iterator {
|
||||
std::list<BugReport*>::iterator impl;
|
||||
public:
|
||||
iterator(std::list<BugReport*>::iterator i) : impl(i) {}
|
||||
iterator& operator++() { ++impl; return *this; }
|
||||
bool operator==(const iterator& I) const { return I.impl == impl; }
|
||||
bool operator!=(const iterator& I) const { return I.impl != impl; }
|
||||
BugReport* operator*() const { return *impl; }
|
||||
BugReport* operator->() const { return *impl; }
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
std::list<BugReport*>::const_iterator impl;
|
||||
public:
|
||||
const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
|
||||
const_iterator& operator++() { ++impl; return *this; }
|
||||
bool operator==(const const_iterator& I) const { return I.impl == impl; }
|
||||
bool operator!=(const const_iterator& I) const { return I.impl != impl; }
|
||||
const BugReport* operator*() const { return *impl; }
|
||||
const BugReport* operator->() const { return *impl; }
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(Reports.begin()); }
|
||||
iterator end() { return iterator(Reports.end()); }
|
||||
|
||||
const_iterator begin() const { return const_iterator(Reports.begin()); }
|
||||
const_iterator end() const { return const_iterator(Reports.end()); }
|
||||
};
|
||||
|
||||
class BugType {
|
||||
private:
|
||||
const std::string Name;
|
||||
const std::string Category;
|
||||
llvm::FoldingSet<BugReportEquivClass> EQClasses;
|
||||
friend class BugReporter;
|
||||
public:
|
||||
BugType(const char *name, const char* cat) : Name(name), Category(cat) {}
|
||||
virtual ~BugType();
|
||||
|
||||
// FIXME: Should these be made strings as well?
|
||||
const std::string& getName() const { return Name; }
|
||||
const std::string& getCategory() const { return Category; }
|
||||
|
||||
virtual void FlushReports(BugReporter& BR);
|
||||
void AddReport(BugReport* BR);
|
||||
|
||||
typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator;
|
||||
iterator begin() { return EQClasses.begin(); }
|
||||
iterator end() { return EQClasses.end(); }
|
||||
|
||||
typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator;
|
||||
const_iterator begin() const { return EQClasses.begin(); }
|
||||
const_iterator end() const { return EQClasses.end(); }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Specialized subclasses of BugReport.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: Collapse this with the default BugReport class.
|
||||
class RangedBugReport : public BugReport {
|
||||
std::vector<SourceRange> Ranges;
|
||||
public:
|
||||
RangedBugReport(BugType& D, const char* description, ExplodedNode<GRState> *n)
|
||||
: BugReport(D, description, n) {}
|
||||
|
||||
RangedBugReport(BugType& D, const char *shortDescription,
|
||||
const char *description, ExplodedNode<GRState> *n)
|
||||
: BugReport(D, shortDescription, description, n) {}
|
||||
|
||||
~RangedBugReport();
|
||||
|
||||
// FIXME: Move this out of line.
|
||||
void addRange(SourceRange R) { Ranges.push_back(R); }
|
||||
|
||||
// FIXME: Move this out of line.
|
||||
void getRanges(BugReporter& BR,const SourceRange*& beg,
|
||||
const SourceRange*& end) {
|
||||
|
||||
if (Ranges.empty()) {
|
||||
beg = NULL;
|
||||
end = NULL;
|
||||
}
|
||||
else {
|
||||
beg = &Ranges[0];
|
||||
end = beg + Ranges.size();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BugReporter and friends.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class BugReporterData {
|
||||
public:
|
||||
virtual ~BugReporterData();
|
||||
virtual Diagnostic& getDiagnostic() = 0;
|
||||
virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
|
||||
virtual ASTContext& getContext() = 0;
|
||||
virtual SourceManager& getSourceManager() = 0;
|
||||
virtual CFG* getCFG() = 0;
|
||||
virtual ParentMap& getParentMap() = 0;
|
||||
virtual LiveVariables* getLiveVariables() = 0;
|
||||
};
|
||||
|
||||
class BugReporter {
|
||||
public:
|
||||
enum Kind { BaseBRKind, GRBugReporterKind };
|
||||
|
||||
private:
|
||||
typedef llvm::ImmutableSet<BugType*> BugTypesTy;
|
||||
BugTypesTy::Factory F;
|
||||
BugTypesTy BugTypes;
|
||||
|
||||
const Kind kind;
|
||||
BugReporterData& D;
|
||||
|
||||
void FlushReport(BugReportEquivClass& EQ);
|
||||
|
||||
protected:
|
||||
BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {}
|
||||
|
||||
public:
|
||||
BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {}
|
||||
virtual ~BugReporter();
|
||||
|
||||
void FlushReports();
|
||||
|
||||
Kind getKind() const { return kind; }
|
||||
|
||||
Diagnostic& getDiagnostic() {
|
||||
return D.getDiagnostic();
|
||||
}
|
||||
|
||||
PathDiagnosticClient* getPathDiagnosticClient() {
|
||||
return D.getPathDiagnosticClient();
|
||||
}
|
||||
|
||||
typedef BugTypesTy::iterator iterator;
|
||||
iterator begin() { return BugTypes.begin(); }
|
||||
iterator end() { return BugTypes.end(); }
|
||||
|
||||
ASTContext& getContext() { return D.getContext(); }
|
||||
|
||||
SourceManager& getSourceManager() { return D.getSourceManager(); }
|
||||
|
||||
CFG* getCFG() { return D.getCFG(); }
|
||||
|
||||
ParentMap& getParentMap() { return D.getParentMap(); }
|
||||
|
||||
LiveVariables* getLiveVariables() { return D.getLiveVariables(); }
|
||||
|
||||
virtual void GeneratePathDiagnostic(PathDiagnostic& PD,
|
||||
BugReportEquivClass& EQ) {}
|
||||
|
||||
void Register(BugType *BT);
|
||||
|
||||
void EmitReport(BugReport *R);
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugStr,
|
||||
SourceLocation Loc,
|
||||
SourceRange* RangeBeg, unsigned NumRanges);
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugCategory,
|
||||
const char* BugStr, SourceLocation Loc,
|
||||
SourceRange* RangeBeg, unsigned NumRanges);
|
||||
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugStr,
|
||||
SourceLocation Loc) {
|
||||
EmitBasicReport(BugName, BugStr, Loc, 0, 0);
|
||||
}
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugCategory,
|
||||
const char* BugStr, SourceLocation Loc) {
|
||||
EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
|
||||
}
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugStr,
|
||||
SourceLocation Loc, SourceRange R) {
|
||||
EmitBasicReport(BugName, BugStr, Loc, &R, 1);
|
||||
}
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* Category,
|
||||
const char* BugStr, SourceLocation Loc, SourceRange R) {
|
||||
EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
|
||||
}
|
||||
|
||||
static bool classof(const BugReporter* R) { return true; }
|
||||
};
|
||||
|
||||
// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
|
||||
class GRBugReporter : public BugReporter {
|
||||
GRExprEngine& Eng;
|
||||
llvm::SmallSet<SymbolRef, 10> NotableSymbols;
|
||||
public:
|
||||
GRBugReporter(BugReporterData& d, GRExprEngine& eng)
|
||||
: BugReporter(d, GRBugReporterKind), Eng(eng) {}
|
||||
|
||||
virtual ~GRBugReporter();
|
||||
|
||||
/// getEngine - Return the analysis engine used to analyze a given
|
||||
/// function or method.
|
||||
GRExprEngine& getEngine() { return Eng; }
|
||||
|
||||
/// getGraph - Get the exploded graph created by the analysis engine
|
||||
/// for the analyzed method or function.
|
||||
ExplodedGraph<GRState>& getGraph();
|
||||
|
||||
/// getStateManager - Return the state manager used by the analysis
|
||||
/// engine.
|
||||
GRStateManager& getStateManager();
|
||||
|
||||
virtual void GeneratePathDiagnostic(PathDiagnostic& PD,
|
||||
BugReportEquivClass& R);
|
||||
|
||||
void addNotableSymbol(SymbolRef Sym) {
|
||||
NotableSymbols.insert(Sym);
|
||||
}
|
||||
|
||||
bool isNotable(SymbolRef Sym) const {
|
||||
return (bool) NotableSymbols.count(Sym);
|
||||
}
|
||||
|
||||
/// classof - Used by isa<>, cast<>, and dyn_cast<>.
|
||||
static bool classof(const BugReporter* R) {
|
||||
return R->getKind() == GRBugReporterKind;
|
||||
}
|
||||
};
|
||||
|
||||
class BugReporterContext {
|
||||
GRBugReporter &BR;
|
||||
std::vector<BugReporterVisitor*> Callbacks;
|
||||
public:
|
||||
BugReporterContext(GRBugReporter& br) : BR(br) {}
|
||||
virtual ~BugReporterContext();
|
||||
|
||||
void addVisitor(BugReporterVisitor* visitor) {
|
||||
if (visitor) Callbacks.push_back(visitor);
|
||||
}
|
||||
|
||||
typedef std::vector<BugReporterVisitor*>::iterator visitor_iterator;
|
||||
visitor_iterator visitor_begin() { return Callbacks.begin(); }
|
||||
visitor_iterator visitor_end() { return Callbacks.end(); }
|
||||
|
||||
GRBugReporter& getBugReporter() { return BR; }
|
||||
|
||||
ExplodedGraph<GRState>& getGraph() { return BR.getGraph(); }
|
||||
|
||||
void addNotableSymbol(SymbolRef Sym) {
|
||||
// FIXME: For now forward to GRBugReporter.
|
||||
BR.addNotableSymbol(Sym);
|
||||
}
|
||||
|
||||
bool isNotable(SymbolRef Sym) const {
|
||||
// FIXME: For now forward to GRBugReporter.
|
||||
return BR.isNotable(Sym);
|
||||
}
|
||||
|
||||
GRStateManager& getStateManager() {
|
||||
return BR.getStateManager();
|
||||
}
|
||||
|
||||
ValueManager& getValueManager() {
|
||||
return getStateManager().getValueManager();
|
||||
}
|
||||
|
||||
ASTContext& getASTContext() {
|
||||
return BR.getContext();
|
||||
}
|
||||
|
||||
SourceManager& getSourceManager() {
|
||||
return BR.getSourceManager();
|
||||
}
|
||||
|
||||
const Decl& getCodeDecl() {
|
||||
return getStateManager().getCodeDecl();
|
||||
}
|
||||
|
||||
const CFG& getCFG() {
|
||||
return *BR.getCFG();
|
||||
}
|
||||
|
||||
virtual BugReport::NodeResolver& getNodeResolver() = 0;
|
||||
};
|
||||
|
||||
class DiagBugReport : public RangedBugReport {
|
||||
std::list<std::string> Strs;
|
||||
FullSourceLoc L;
|
||||
public:
|
||||
DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) :
|
||||
RangedBugReport(D, desc, 0), L(l) {}
|
||||
|
||||
virtual ~DiagBugReport() {}
|
||||
|
||||
// FIXME: Move out-of-line (virtual function).
|
||||
SourceLocation getLocation() const { return L; }
|
||||
|
||||
void addString(const std::string& s) { Strs.push_back(s); }
|
||||
|
||||
typedef std::list<std::string>::const_iterator str_iterator;
|
||||
str_iterator str_begin() const { return Strs.begin(); }
|
||||
str_iterator str_end() const { return Strs.end(); }
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
67
include/clang/Analysis/PathSensitive/ConstraintManager.h
Normal file
67
include/clang/Analysis/PathSensitive/ConstraintManager.h
Normal file
@ -0,0 +1,67 @@
|
||||
//== ConstraintManager.h - Constraints on symbolic 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 defined the interface to manage constraints on symbolic values.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H
|
||||
#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H
|
||||
|
||||
// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
|
||||
#include "clang/Analysis/PathSensitive/Store.h"
|
||||
|
||||
namespace llvm {
|
||||
class APSInt;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRState;
|
||||
class GRStateManager;
|
||||
class SVal;
|
||||
|
||||
class ConstraintManager {
|
||||
public:
|
||||
virtual ~ConstraintManager();
|
||||
virtual const GRState* Assume(const GRState* St, SVal Cond,
|
||||
bool Assumption, bool& isFeasible) = 0;
|
||||
|
||||
virtual const GRState* AssumeInBound(const GRState* St, SVal Idx,
|
||||
SVal UpperBound, bool Assumption,
|
||||
bool& isFeasible) = 0;
|
||||
|
||||
virtual const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym)
|
||||
const = 0;
|
||||
|
||||
virtual bool isEqual(const GRState* St, SymbolRef sym,
|
||||
const llvm::APSInt& V) const = 0;
|
||||
|
||||
virtual const GRState* RemoveDeadBindings(const GRState* St,
|
||||
SymbolReaper& SymReaper) = 0;
|
||||
|
||||
virtual void print(const GRState* St, std::ostream& Out,
|
||||
const char* nl, const char *sep) = 0;
|
||||
|
||||
virtual void EndPath(const GRState* St) {}
|
||||
|
||||
/// canReasonAbout - Not all ConstraintManagers can accurately reason about
|
||||
/// all SVal values. This method returns true if the ConstraintManager can
|
||||
/// reasonably handle a given SVal value. This is typically queried by
|
||||
/// GRExprEngine to determine if the value should be replaced with a
|
||||
/// conjured symbolic value in order to recover some precision.
|
||||
virtual bool canReasonAbout(SVal X) const = 0;
|
||||
};
|
||||
|
||||
ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr);
|
||||
ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
151
include/clang/Analysis/PathSensitive/Environment.h
Normal file
151
include/clang/Analysis/PathSensitive/Environment.h
Normal file
@ -0,0 +1,151 @@
|
||||
//== Environment.h - Map from Stmt* to Locations/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 defined the Environment and EnvironmentManager classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_ENVIRONMENT_H
|
||||
#define LLVM_CLANG_ANALYSIS_ENVIRONMENT_H
|
||||
|
||||
// For using typedefs in StoreManager. Should find a better place for these
|
||||
// typedefs.
|
||||
#include "clang/Analysis/PathSensitive/Store.h"
|
||||
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class EnvironmentManager;
|
||||
class BasicValueFactory;
|
||||
class LiveVariables;
|
||||
|
||||
class Environment : public llvm::FoldingSetNode {
|
||||
private:
|
||||
|
||||
friend class EnvironmentManager;
|
||||
|
||||
// Type definitions.
|
||||
typedef llvm::ImmutableMap<Stmt*,SVal> BindingsTy;
|
||||
|
||||
// Data.
|
||||
BindingsTy SubExprBindings;
|
||||
BindingsTy BlkExprBindings;
|
||||
|
||||
Environment(BindingsTy seb, BindingsTy beb)
|
||||
: SubExprBindings(seb), BlkExprBindings(beb) {}
|
||||
|
||||
public:
|
||||
|
||||
typedef BindingsTy::iterator seb_iterator;
|
||||
seb_iterator seb_begin() const { return SubExprBindings.begin(); }
|
||||
seb_iterator seb_end() const { return SubExprBindings.end(); }
|
||||
|
||||
typedef BindingsTy::iterator beb_iterator;
|
||||
beb_iterator beb_begin() const { return BlkExprBindings.begin(); }
|
||||
beb_iterator beb_end() const { return BlkExprBindings.end(); }
|
||||
|
||||
SVal LookupSubExpr(Stmt* E) const {
|
||||
const SVal* X = SubExprBindings.lookup(cast<Expr>(E));
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
SVal LookupBlkExpr(Stmt* E) const {
|
||||
const SVal* X = BlkExprBindings.lookup(E);
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
SVal LookupExpr(Stmt* E) const {
|
||||
const SVal* X = SubExprBindings.lookup(E);
|
||||
if (X) return *X;
|
||||
X = BlkExprBindings.lookup(E);
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
SVal GetSVal(Stmt* Ex, BasicValueFactory& BasicVals) const;
|
||||
SVal GetBlkExprSVal(Stmt* Ex, BasicValueFactory& BasicVals) const;
|
||||
|
||||
/// Profile - Profile the contents of an Environment object for use
|
||||
/// in a FoldingSet.
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) {
|
||||
E->SubExprBindings.Profile(ID);
|
||||
E->BlkExprBindings.Profile(ID);
|
||||
}
|
||||
|
||||
/// Profile - Used to profile the contents of this object for inclusion
|
||||
/// in a FoldingSet.
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
Profile(ID, this);
|
||||
}
|
||||
|
||||
bool operator==(const Environment& RHS) const {
|
||||
return SubExprBindings == RHS.SubExprBindings &&
|
||||
BlkExprBindings == RHS.BlkExprBindings;
|
||||
}
|
||||
};
|
||||
|
||||
class EnvironmentManager {
|
||||
private:
|
||||
typedef Environment::BindingsTy::Factory FactoryTy;
|
||||
FactoryTy F;
|
||||
|
||||
public:
|
||||
|
||||
EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {}
|
||||
~EnvironmentManager() {}
|
||||
|
||||
/// RemoveBlkExpr - Return a new environment object with the same bindings as
|
||||
/// the provided environment except with any bindings for the provided Stmt*
|
||||
/// removed. This method only removes bindings for block-level expressions.
|
||||
/// Using this method on a non-block level expression will return the
|
||||
/// same environment object.
|
||||
Environment RemoveBlkExpr(const Environment& Env, Stmt* E) {
|
||||
return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E));
|
||||
}
|
||||
|
||||
Environment RemoveSubExpr(const Environment& Env, Stmt* E) {
|
||||
return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
Environment AddBlkExpr(const Environment& Env, Stmt* E, SVal V) {
|
||||
return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V));
|
||||
}
|
||||
|
||||
Environment AddSubExpr(const Environment& Env, Stmt* E, SVal V) {
|
||||
return Environment(F.Add(Env.SubExprBindings, E, V), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
/// RemoveSubExprBindings - Return a new environment object with
|
||||
/// the same bindings as the provided environment except with all the
|
||||
/// subexpression bindings removed.
|
||||
Environment RemoveSubExprBindings(const Environment& Env) {
|
||||
return Environment(F.GetEmptyMap(), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
Environment getInitialEnvironment() {
|
||||
return Environment(F.GetEmptyMap(), F.GetEmptyMap());
|
||||
}
|
||||
|
||||
Environment BindExpr(const Environment& Env, Stmt* E, SVal V,
|
||||
bool isBlkExpr, bool Invalidate);
|
||||
|
||||
Environment
|
||||
RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper,
|
||||
GRStateManager& StateMgr, const GRState *state,
|
||||
llvm::SmallVectorImpl<const MemRegion*>& DRoots);
|
||||
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
582
include/clang/Analysis/PathSensitive/ExplodedGraph.h
Normal file
582
include/clang/Analysis/PathSensitive/ExplodedGraph.h
Normal file
@ -0,0 +1,582 @@
|
||||
//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- 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 template classes ExplodedNode and ExplodedGraph,
|
||||
// which represent a path-sensitive, intra-procedural "exploded graph."
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
|
||||
#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
|
||||
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRCoreEngineImpl;
|
||||
class ExplodedNodeImpl;
|
||||
class CFG;
|
||||
class ASTContext;
|
||||
|
||||
class GRStmtNodeBuilderImpl;
|
||||
class GRBranchNodeBuilderImpl;
|
||||
class GRIndirectGotoNodeBuilderImpl;
|
||||
class GRSwitchNodeBuilderImpl;
|
||||
class GREndPathNodebuilderImpl;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ExplodedGraph "implementation" classes. These classes are not typed to
|
||||
// contain a specific kind of state. Typed-specialized versions are defined
|
||||
// on top of these classes.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class ExplodedNodeImpl : public llvm::FoldingSetNode {
|
||||
protected:
|
||||
friend class ExplodedGraphImpl;
|
||||
friend class GRCoreEngineImpl;
|
||||
friend class GRStmtNodeBuilderImpl;
|
||||
friend class GRBranchNodeBuilderImpl;
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
friend class GREndPathNodeBuilderImpl;
|
||||
|
||||
class NodeGroup {
|
||||
enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
|
||||
uintptr_t P;
|
||||
|
||||
unsigned getKind() const {
|
||||
return P & 0x1;
|
||||
}
|
||||
|
||||
void* getPtr() const {
|
||||
assert (!getFlag());
|
||||
return reinterpret_cast<void*>(P & ~Mask);
|
||||
}
|
||||
|
||||
ExplodedNodeImpl* getNode() const {
|
||||
return reinterpret_cast<ExplodedNodeImpl*>(getPtr());
|
||||
}
|
||||
|
||||
public:
|
||||
NodeGroup() : P(0) {}
|
||||
|
||||
~NodeGroup();
|
||||
|
||||
ExplodedNodeImpl** begin() const;
|
||||
|
||||
ExplodedNodeImpl** end() const;
|
||||
|
||||
unsigned size() const;
|
||||
|
||||
bool empty() const { return size() == 0; }
|
||||
|
||||
void addNode(ExplodedNodeImpl* N);
|
||||
|
||||
void setFlag() {
|
||||
assert (P == 0);
|
||||
P = AuxFlag;
|
||||
}
|
||||
|
||||
bool getFlag() const {
|
||||
return P & AuxFlag ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
/// Location - The program location (within a function body) associated
|
||||
/// with this node.
|
||||
const ProgramPoint Location;
|
||||
|
||||
/// State - The state associated with this node.
|
||||
const void* State;
|
||||
|
||||
/// Preds - The predecessors of this node.
|
||||
NodeGroup Preds;
|
||||
|
||||
/// Succs - The successors of this node.
|
||||
NodeGroup Succs;
|
||||
|
||||
/// Construct a ExplodedNodeImpl with the provided location and state.
|
||||
explicit ExplodedNodeImpl(const ProgramPoint& loc, const void* state)
|
||||
: Location(loc), State(state) {}
|
||||
|
||||
/// addPredeccessor - Adds a predecessor to the current node, and
|
||||
/// in tandem add this node as a successor of the other node.
|
||||
void addPredecessor(ExplodedNodeImpl* V);
|
||||
|
||||
public:
|
||||
|
||||
/// getLocation - Returns the edge associated with the given node.
|
||||
ProgramPoint getLocation() const { return Location; }
|
||||
|
||||
template <typename T>
|
||||
const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
|
||||
|
||||
unsigned succ_size() const { return Succs.size(); }
|
||||
unsigned pred_size() const { return Preds.size(); }
|
||||
bool succ_empty() const { return Succs.empty(); }
|
||||
bool pred_empty() const { return Preds.empty(); }
|
||||
|
||||
bool isSink() const { return Succs.getFlag(); }
|
||||
void markAsSink() { Succs.setFlag(); }
|
||||
|
||||
// For debugging.
|
||||
|
||||
public:
|
||||
|
||||
class Auditor {
|
||||
public:
|
||||
virtual ~Auditor();
|
||||
virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) = 0;
|
||||
};
|
||||
|
||||
static void SetAuditor(Auditor* A);
|
||||
};
|
||||
|
||||
|
||||
template <typename StateTy>
|
||||
struct GRTrait {
|
||||
static inline void Profile(llvm::FoldingSetNodeID& ID, const StateTy* St) {
|
||||
St->Profile(ID);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename StateTy>
|
||||
class ExplodedNode : public ExplodedNodeImpl {
|
||||
public:
|
||||
/// Construct a ExplodedNodeImpl with the given node ID, program edge,
|
||||
/// and state.
|
||||
explicit ExplodedNode(const ProgramPoint& loc, const StateTy* St)
|
||||
: ExplodedNodeImpl(loc, St) {}
|
||||
|
||||
/// getState - Returns the state associated with the node.
|
||||
inline const StateTy* getState() const {
|
||||
return static_cast<const StateTy*>(State);
|
||||
}
|
||||
|
||||
// Profiling (for FoldingSet).
|
||||
|
||||
static inline void Profile(llvm::FoldingSetNodeID& ID,
|
||||
const ProgramPoint& Loc,
|
||||
const StateTy* state) {
|
||||
ID.Add(Loc);
|
||||
GRTrait<StateTy>::Profile(ID, state);
|
||||
}
|
||||
|
||||
inline void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
Profile(ID, getLocation(), getState());
|
||||
}
|
||||
|
||||
void addPredecessor(ExplodedNode* V) {
|
||||
ExplodedNodeImpl::addPredecessor(V);
|
||||
}
|
||||
|
||||
ExplodedNode* getFirstPred() {
|
||||
return pred_empty() ? NULL : *(pred_begin());
|
||||
}
|
||||
|
||||
const ExplodedNode* getFirstPred() const {
|
||||
return const_cast<ExplodedNode*>(this)->getFirstPred();
|
||||
}
|
||||
|
||||
// Iterators over successor and predecessor vertices.
|
||||
typedef ExplodedNode** succ_iterator;
|
||||
typedef const ExplodedNode* const * const_succ_iterator;
|
||||
typedef ExplodedNode** pred_iterator;
|
||||
typedef const ExplodedNode* const * const_pred_iterator;
|
||||
|
||||
pred_iterator pred_begin() { return (ExplodedNode**) Preds.begin(); }
|
||||
pred_iterator pred_end() { return (ExplodedNode**) Preds.end(); }
|
||||
|
||||
const_pred_iterator pred_begin() const {
|
||||
return const_cast<ExplodedNode*>(this)->pred_begin();
|
||||
}
|
||||
const_pred_iterator pred_end() const {
|
||||
return const_cast<ExplodedNode*>(this)->pred_end();
|
||||
}
|
||||
|
||||
succ_iterator succ_begin() { return (ExplodedNode**) Succs.begin(); }
|
||||
succ_iterator succ_end() { return (ExplodedNode**) Succs.end(); }
|
||||
|
||||
const_succ_iterator succ_begin() const {
|
||||
return const_cast<ExplodedNode*>(this)->succ_begin();
|
||||
}
|
||||
const_succ_iterator succ_end() const {
|
||||
return const_cast<ExplodedNode*>(this)->succ_end();
|
||||
}
|
||||
};
|
||||
|
||||
class InterExplodedGraphMapImpl;
|
||||
|
||||
class ExplodedGraphImpl {
|
||||
protected:
|
||||
friend class GRCoreEngineImpl;
|
||||
friend class GRStmtNodeBuilderImpl;
|
||||
friend class GRBranchNodeBuilderImpl;
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
friend class GREndPathNodeBuilderImpl;
|
||||
|
||||
// Type definitions.
|
||||
typedef llvm::SmallVector<ExplodedNodeImpl*,2> RootsTy;
|
||||
typedef llvm::SmallVector<ExplodedNodeImpl*,10> EndNodesTy;
|
||||
|
||||
/// Roots - The roots of the simulation graph. Usually there will be only
|
||||
/// one, but clients are free to establish multiple subgraphs within a single
|
||||
/// SimulGraph. Moreover, these subgraphs can often merge when paths from
|
||||
/// different roots reach the same state at the same program location.
|
||||
RootsTy Roots;
|
||||
|
||||
/// EndNodes - The nodes in the simulation graph which have been
|
||||
/// specially marked as the endpoint of an abstract simulation path.
|
||||
EndNodesTy EndNodes;
|
||||
|
||||
/// Allocator - BumpPtrAllocator to create nodes.
|
||||
llvm::BumpPtrAllocator Allocator;
|
||||
|
||||
/// cfg - The CFG associated with this analysis graph.
|
||||
CFG& cfg;
|
||||
|
||||
/// CodeDecl - The declaration containing the code being analyzed. This
|
||||
/// can be a FunctionDecl or and ObjCMethodDecl.
|
||||
Decl& CodeDecl;
|
||||
|
||||
/// Ctx - The ASTContext used to "interpret" CodeDecl.
|
||||
ASTContext& Ctx;
|
||||
|
||||
/// NumNodes - The number of nodes in the graph.
|
||||
unsigned NumNodes;
|
||||
|
||||
/// getNodeImpl - Retrieve the node associated with a (Location,State)
|
||||
/// pair, where 'State' is represented as an opaque void*. This method
|
||||
/// is intended to be used only by GRCoreEngineImpl.
|
||||
virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
|
||||
const void* State,
|
||||
bool* IsNew) = 0;
|
||||
|
||||
virtual ExplodedGraphImpl* MakeEmptyGraph() const = 0;
|
||||
|
||||
/// addRoot - Add an untyped node to the set of roots.
|
||||
ExplodedNodeImpl* addRoot(ExplodedNodeImpl* V) {
|
||||
Roots.push_back(V);
|
||||
return V;
|
||||
}
|
||||
|
||||
/// addEndOfPath - Add an untyped node to the set of EOP nodes.
|
||||
ExplodedNodeImpl* addEndOfPath(ExplodedNodeImpl* V) {
|
||||
EndNodes.push_back(V);
|
||||
return V;
|
||||
}
|
||||
|
||||
// ctor.
|
||||
ExplodedGraphImpl(CFG& c, Decl& cd, ASTContext& ctx)
|
||||
: cfg(c), CodeDecl(cd), Ctx(ctx), NumNodes(0) {}
|
||||
|
||||
public:
|
||||
virtual ~ExplodedGraphImpl() {}
|
||||
|
||||
unsigned num_roots() const { return Roots.size(); }
|
||||
unsigned num_eops() const { return EndNodes.size(); }
|
||||
|
||||
bool empty() const { return NumNodes == 0; }
|
||||
unsigned size() const { return NumNodes; }
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() { return Allocator; }
|
||||
CFG& getCFG() { return cfg; }
|
||||
ASTContext& getContext() { return Ctx; }
|
||||
|
||||
Decl& getCodeDecl() { return CodeDecl; }
|
||||
const Decl& getCodeDecl() const { return CodeDecl; }
|
||||
|
||||
const FunctionDecl* getFunctionDecl() const {
|
||||
return llvm::dyn_cast<FunctionDecl>(&CodeDecl);
|
||||
}
|
||||
|
||||
typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> NodeMap;
|
||||
|
||||
ExplodedGraphImpl* Trim(const ExplodedNodeImpl* const * NBeg,
|
||||
const ExplodedNodeImpl* const * NEnd,
|
||||
InterExplodedGraphMapImpl *M,
|
||||
llvm::DenseMap<const void*, const void*> *InverseMap)
|
||||
const;
|
||||
};
|
||||
|
||||
class InterExplodedGraphMapImpl {
|
||||
llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> M;
|
||||
friend class ExplodedGraphImpl;
|
||||
void add(const ExplodedNodeImpl* From, ExplodedNodeImpl* To);
|
||||
|
||||
protected:
|
||||
ExplodedNodeImpl* getMappedImplNode(const ExplodedNodeImpl* N) const;
|
||||
|
||||
InterExplodedGraphMapImpl();
|
||||
public:
|
||||
virtual ~InterExplodedGraphMapImpl() {}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Type-specialized ExplodedGraph classes.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename STATE>
|
||||
class InterExplodedGraphMap : public InterExplodedGraphMapImpl {
|
||||
public:
|
||||
InterExplodedGraphMap() {};
|
||||
~InterExplodedGraphMap() {};
|
||||
|
||||
ExplodedNode<STATE>* getMappedNode(const ExplodedNode<STATE>* N) const {
|
||||
return static_cast<ExplodedNode<STATE>*>(getMappedImplNode(N));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename STATE>
|
||||
class ExplodedGraph : public ExplodedGraphImpl {
|
||||
public:
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
typedef llvm::FoldingSet<NodeTy> AllNodesTy;
|
||||
|
||||
protected:
|
||||
/// Nodes - The nodes in the graph.
|
||||
AllNodesTy Nodes;
|
||||
|
||||
protected:
|
||||
virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
|
||||
const void* State,
|
||||
bool* IsNew) {
|
||||
|
||||
return getNode(L, static_cast<const StateTy*>(State), IsNew);
|
||||
}
|
||||
|
||||
virtual ExplodedGraphImpl* MakeEmptyGraph() const {
|
||||
return new ExplodedGraph(cfg, CodeDecl, Ctx);
|
||||
}
|
||||
|
||||
public:
|
||||
ExplodedGraph(CFG& c, Decl& cd, ASTContext& ctx)
|
||||
: ExplodedGraphImpl(c, cd, ctx) {}
|
||||
|
||||
/// getNode - Retrieve the node associated with a (Location,State) pair,
|
||||
/// where the 'Location' is a ProgramPoint in the CFG. If no node for
|
||||
/// this pair exists, it is created. IsNew is set to true if
|
||||
/// the node was freshly created.
|
||||
NodeTy* getNode(const ProgramPoint& L, const StateTy* State,
|
||||
bool* IsNew = NULL) {
|
||||
|
||||
// Profile 'State' to determine if we already have an existing node.
|
||||
llvm::FoldingSetNodeID profile;
|
||||
void* InsertPos = 0;
|
||||
|
||||
NodeTy::Profile(profile, L, State);
|
||||
NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
|
||||
|
||||
if (!V) {
|
||||
// Allocate a new node.
|
||||
V = (NodeTy*) Allocator.Allocate<NodeTy>();
|
||||
new (V) NodeTy(L, State);
|
||||
|
||||
// Insert the node into the node set and return it.
|
||||
Nodes.InsertNode(V, InsertPos);
|
||||
|
||||
++NumNodes;
|
||||
|
||||
if (IsNew) *IsNew = true;
|
||||
}
|
||||
else
|
||||
if (IsNew) *IsNew = false;
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
// Iterators.
|
||||
typedef NodeTy** roots_iterator;
|
||||
typedef const NodeTy** const_roots_iterator;
|
||||
typedef NodeTy** eop_iterator;
|
||||
typedef const NodeTy** const_eop_iterator;
|
||||
typedef typename AllNodesTy::iterator node_iterator;
|
||||
typedef typename AllNodesTy::const_iterator const_node_iterator;
|
||||
|
||||
node_iterator nodes_begin() {
|
||||
return Nodes.begin();
|
||||
}
|
||||
|
||||
node_iterator nodes_end() {
|
||||
return Nodes.end();
|
||||
}
|
||||
|
||||
const_node_iterator nodes_begin() const {
|
||||
return Nodes.begin();
|
||||
}
|
||||
|
||||
const_node_iterator nodes_end() const {
|
||||
return Nodes.end();
|
||||
}
|
||||
|
||||
roots_iterator roots_begin() {
|
||||
return reinterpret_cast<roots_iterator>(Roots.begin());
|
||||
}
|
||||
|
||||
roots_iterator roots_end() {
|
||||
return reinterpret_cast<roots_iterator>(Roots.end());
|
||||
}
|
||||
|
||||
const_roots_iterator roots_begin() const {
|
||||
return const_cast<ExplodedGraph>(this)->roots_begin();
|
||||
}
|
||||
|
||||
const_roots_iterator roots_end() const {
|
||||
return const_cast<ExplodedGraph>(this)->roots_end();
|
||||
}
|
||||
|
||||
eop_iterator eop_begin() {
|
||||
return reinterpret_cast<eop_iterator>(EndNodes.begin());
|
||||
}
|
||||
|
||||
eop_iterator eop_end() {
|
||||
return reinterpret_cast<eop_iterator>(EndNodes.end());
|
||||
}
|
||||
|
||||
const_eop_iterator eop_begin() const {
|
||||
return const_cast<ExplodedGraph>(this)->eop_begin();
|
||||
}
|
||||
|
||||
const_eop_iterator eop_end() const {
|
||||
return const_cast<ExplodedGraph>(this)->eop_end();
|
||||
}
|
||||
|
||||
std::pair<ExplodedGraph*, InterExplodedGraphMap<STATE>*>
|
||||
Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
|
||||
llvm::DenseMap<const void*, const void*> *InverseMap = 0) const {
|
||||
|
||||
if (NBeg == NEnd)
|
||||
return std::make_pair((ExplodedGraph*) 0,
|
||||
(InterExplodedGraphMap<STATE>*) 0);
|
||||
|
||||
assert (NBeg < NEnd);
|
||||
|
||||
const ExplodedNodeImpl* const* NBegImpl =
|
||||
(const ExplodedNodeImpl* const*) NBeg;
|
||||
const ExplodedNodeImpl* const* NEndImpl =
|
||||
(const ExplodedNodeImpl* const*) NEnd;
|
||||
|
||||
llvm::OwningPtr<InterExplodedGraphMap<STATE> >
|
||||
M(new InterExplodedGraphMap<STATE>());
|
||||
|
||||
ExplodedGraphImpl* G = ExplodedGraphImpl::Trim(NBegImpl, NEndImpl, M.get(),
|
||||
InverseMap);
|
||||
|
||||
return std::make_pair(static_cast<ExplodedGraph*>(G), M.take());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename StateTy>
|
||||
class ExplodedNodeSet {
|
||||
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,5> ImplTy;
|
||||
ImplTy Impl;
|
||||
|
||||
public:
|
||||
ExplodedNodeSet(NodeTy* N) {
|
||||
assert (N && !static_cast<ExplodedNodeImpl*>(N)->isSink());
|
||||
Impl.insert(N);
|
||||
}
|
||||
|
||||
ExplodedNodeSet() {}
|
||||
|
||||
inline void Add(NodeTy* N) {
|
||||
if (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()) Impl.insert(N);
|
||||
}
|
||||
|
||||
typedef typename ImplTy::iterator iterator;
|
||||
typedef typename ImplTy::const_iterator const_iterator;
|
||||
|
||||
inline unsigned size() const { return Impl.size(); }
|
||||
inline bool empty() const { return Impl.empty(); }
|
||||
|
||||
inline void clear() { Impl.clear(); }
|
||||
|
||||
inline iterator begin() { return Impl.begin(); }
|
||||
inline iterator end() { return Impl.end(); }
|
||||
|
||||
inline const_iterator begin() const { return Impl.begin(); }
|
||||
inline const_iterator end() const { return Impl.end(); }
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
// GraphTraits
|
||||
|
||||
namespace llvm {
|
||||
template<typename StateTy>
|
||||
struct GraphTraits<clang::ExplodedNode<StateTy>*> {
|
||||
typedef clang::ExplodedNode<StateTy> NodeType;
|
||||
typedef typename NodeType::succ_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<NodeType*> nodes_iterator;
|
||||
|
||||
static inline NodeType* getEntryNode(NodeType* N) {
|
||||
return N;
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
return N->succ_begin();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
return N->succ_end();
|
||||
}
|
||||
|
||||
static inline nodes_iterator nodes_begin(NodeType* N) {
|
||||
return df_begin(N);
|
||||
}
|
||||
|
||||
static inline nodes_iterator nodes_end(NodeType* N) {
|
||||
return df_end(N);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename StateTy>
|
||||
struct GraphTraits<const clang::ExplodedNode<StateTy>*> {
|
||||
typedef const clang::ExplodedNode<StateTy> NodeType;
|
||||
typedef typename NodeType::succ_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<NodeType*> nodes_iterator;
|
||||
|
||||
static inline NodeType* getEntryNode(NodeType* N) {
|
||||
return N;
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
return N->succ_begin();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
return N->succ_end();
|
||||
}
|
||||
|
||||
static inline nodes_iterator nodes_begin(NodeType* N) {
|
||||
return df_begin(N);
|
||||
}
|
||||
|
||||
static inline nodes_iterator nodes_end(NodeType* N) {
|
||||
return df_end(N);
|
||||
}
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
39
include/clang/Analysis/PathSensitive/GRAuditor.h
Normal file
39
include/clang/Analysis/PathSensitive/GRAuditor.h
Normal file
@ -0,0 +1,39 @@
|
||||
//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- 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 GRAuditor and its primary subclasses, an interface
|
||||
// to audit the creation of ExplodedNodes. This interface can be used
|
||||
// to implement simple checkers that do not mutate analysis state but
|
||||
// instead operate by perfoming simple logical checks at key monitoring
|
||||
// locations (e.g., function calls).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR
|
||||
#define LLVM_CLANG_ANALYSIS_GRAUDITOR
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
template <typename STATE>
|
||||
class GRAuditor {
|
||||
public:
|
||||
typedef ExplodedNode<STATE> NodeTy;
|
||||
typedef typename STATE::ManagerTy ManagerTy;
|
||||
|
||||
virtual ~GRAuditor() {}
|
||||
virtual bool Audit(NodeTy* N, ManagerTy& M) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
50
include/clang/Analysis/PathSensitive/GRBlockCounter.h
Normal file
50
include/clang/Analysis/PathSensitive/GRBlockCounter.h
Normal file
@ -0,0 +1,50 @@
|
||||
//==- GRBlockCounter.h - ADT for counting block visits -------------*- 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 GRBlockCounter, an abstract data type used to count
|
||||
// the number of times a given block has been visited along a path
|
||||
// analyzed by GRCoreEngine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER
|
||||
#define LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER
|
||||
|
||||
namespace llvm {
|
||||
class BumpPtrAllocator;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRBlockCounter {
|
||||
void* Data;
|
||||
|
||||
GRBlockCounter(void* D) : Data(D) {}
|
||||
|
||||
public:
|
||||
GRBlockCounter() : Data(0) {}
|
||||
|
||||
unsigned getNumVisited(unsigned BlockID) const;
|
||||
|
||||
class Factory {
|
||||
void* F;
|
||||
public:
|
||||
Factory(llvm::BumpPtrAllocator& Alloc);
|
||||
~Factory();
|
||||
|
||||
GRBlockCounter GetEmptyCounter();
|
||||
GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID);
|
||||
};
|
||||
|
||||
friend class Factory;
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
668
include/clang/Analysis/PathSensitive/GRCoreEngine.h
Normal file
668
include/clang/Analysis/PathSensitive/GRCoreEngine.h
Normal file
@ -0,0 +1,668 @@
|
||||
//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- 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 a generic engine for intraprocedural, path-sensitive,
|
||||
// dataflow analysis via graph reachability.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRENGINE
|
||||
#define LLVM_CLANG_ANALYSIS_GRENGINE
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
#include "clang/Analysis/PathSensitive/GRWorkList.h"
|
||||
#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
|
||||
#include "clang/Analysis/PathSensitive/GRAuditor.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRStmtNodeBuilderImpl;
|
||||
class GRBranchNodeBuilderImpl;
|
||||
class GRIndirectGotoNodeBuilderImpl;
|
||||
class GRSwitchNodeBuilderImpl;
|
||||
class GREndPathNodeBuilderImpl;
|
||||
class GRWorkList;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// GRCoreEngineImpl - Implements the core logic of the graph-reachability
|
||||
/// analysis. It traverses the CFG and generates the ExplodedGraph.
|
||||
/// Program "states" are treated as opaque void pointers.
|
||||
/// The template class GRCoreEngine (which subclasses GRCoreEngineImpl)
|
||||
/// provides the matching component to the engine that knows the actual types
|
||||
/// for states. Note that this engine only dispatches to transfer functions
|
||||
/// at the statement and block-level. The analyses themselves must implement
|
||||
/// any transfer function logic and the sub-expression level (if any).
|
||||
class GRCoreEngineImpl {
|
||||
protected:
|
||||
friend class GRStmtNodeBuilderImpl;
|
||||
friend class GRBranchNodeBuilderImpl;
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
friend class GREndPathNodeBuilderImpl;
|
||||
|
||||
/// G - The simulation graph. Each node is a (location,state) pair.
|
||||
llvm::OwningPtr<ExplodedGraphImpl> G;
|
||||
|
||||
/// WList - A set of queued nodes that need to be processed by the
|
||||
/// worklist algorithm. It is up to the implementation of WList to decide
|
||||
/// the order that nodes are processed.
|
||||
GRWorkList* WList;
|
||||
|
||||
/// BCounterFactory - A factory object for created GRBlockCounter objects.
|
||||
/// These are used to record for key nodes in the ExplodedGraph the
|
||||
/// number of times different CFGBlocks have been visited along a path.
|
||||
GRBlockCounter::Factory BCounterFactory;
|
||||
|
||||
void GenerateNode(const ProgramPoint& Loc, const void* State,
|
||||
ExplodedNodeImpl* Pred);
|
||||
|
||||
/// getInitialState - Gets the void* representing the initial 'state'
|
||||
/// of the analysis. This is simply a wrapper (implemented
|
||||
/// in GRCoreEngine) that performs type erasure on the initial
|
||||
/// state returned by the checker object.
|
||||
virtual const void* getInitialState() = 0;
|
||||
|
||||
void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred);
|
||||
void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred);
|
||||
void HandleBlockExit(CFGBlock* B, ExplodedNodeImpl* Pred);
|
||||
void HandlePostStmt(const PostStmt& S, CFGBlock* B,
|
||||
unsigned StmtIdx, ExplodedNodeImpl *Pred);
|
||||
|
||||
void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
|
||||
ExplodedNodeImpl* Pred);
|
||||
|
||||
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
|
||||
GRBlockCounter BC) = 0;
|
||||
|
||||
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
|
||||
GRBranchNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
private:
|
||||
GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
|
||||
GRCoreEngineImpl& operator=(const GRCoreEngineImpl&);
|
||||
|
||||
protected:
|
||||
GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl)
|
||||
: G(g), WList(wl), BCounterFactory(g->getAllocator()) {}
|
||||
|
||||
public:
|
||||
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
|
||||
/// steps. Returns true if there is still simulation state on the worklist.
|
||||
bool ExecuteWorkList(unsigned Steps);
|
||||
|
||||
virtual ~GRCoreEngineImpl();
|
||||
|
||||
CFG& getCFG() { return G->getCFG(); }
|
||||
};
|
||||
|
||||
class GRStmtNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock& B;
|
||||
const unsigned Idx;
|
||||
ExplodedNodeImpl* Pred;
|
||||
ExplodedNodeImpl* LastNode;
|
||||
|
||||
typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy;
|
||||
DeferredTy Deferred;
|
||||
|
||||
void GenerateAutoTransition(ExplodedNodeImpl* N);
|
||||
|
||||
public:
|
||||
GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx,
|
||||
ExplodedNodeImpl* N, GRCoreEngineImpl* e);
|
||||
|
||||
~GRStmtNodeBuilderImpl();
|
||||
|
||||
ExplodedNodeImpl* getBasePredecessor() const { return Pred; }
|
||||
|
||||
ExplodedNodeImpl* getLastNode() const {
|
||||
return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(PostStmt PP, const void* State, ExplodedNodeImpl* Pred);
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
|
||||
const void *tag = 0);
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(Stmt* S, const void* State,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
|
||||
const void *tag = 0) {
|
||||
ExplodedNodeImpl* N = getLastNode();
|
||||
assert (N && "Predecessor of new node is infeasible.");
|
||||
return generateNodeImpl(S, State, N, K, tag);
|
||||
}
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(Stmt* S, const void* State, const void *tag = 0) {
|
||||
ExplodedNodeImpl* N = getLastNode();
|
||||
assert (N && "Predecessor of new node is infeasible.");
|
||||
return generateNodeImpl(S, State, N, ProgramPoint::PostStmtKind, tag);
|
||||
}
|
||||
|
||||
/// getStmt - Return the current block-level expression associated with
|
||||
/// this builder.
|
||||
Stmt* getStmt() const { return B[Idx]; }
|
||||
|
||||
/// getBlock - Return the CFGBlock associated with the block-level expression
|
||||
/// of this builder.
|
||||
CFGBlock* getBlock() const { return &B; }
|
||||
};
|
||||
|
||||
|
||||
template<typename STATE>
|
||||
class GRStmtNodeBuilder {
|
||||
public:
|
||||
typedef STATE StateTy;
|
||||
typedef typename StateTy::ManagerTy StateManagerTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
|
||||
private:
|
||||
GRStmtNodeBuilderImpl& NB;
|
||||
StateManagerTy& Mgr;
|
||||
const StateTy* CleanedState;
|
||||
GRAuditor<StateTy>* Auditor;
|
||||
|
||||
public:
|
||||
GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) :
|
||||
NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false),
|
||||
BuildSinks(false), HasGeneratedNode(false),
|
||||
PointKind(ProgramPoint::PostStmtKind), Tag(0) {
|
||||
|
||||
CleanedState = getLastNode()->getState();
|
||||
}
|
||||
|
||||
void setAuditor(GRAuditor<StateTy>* A) {
|
||||
Auditor = A;
|
||||
}
|
||||
|
||||
NodeTy* getLastNode() const {
|
||||
return static_cast<NodeTy*>(NB.getLastNode());
|
||||
}
|
||||
|
||||
NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) {
|
||||
HasGeneratedNode = true;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(PP, St, Pred));
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred,
|
||||
ProgramPoint::Kind K) {
|
||||
HasGeneratedNode = true;
|
||||
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K, Tag));
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred) {
|
||||
return generateNode(S, St, Pred, PointKind);
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St, ProgramPoint::Kind K) {
|
||||
HasGeneratedNode = true;
|
||||
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K, Tag));
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St) {
|
||||
return generateNode(S, St, PointKind);
|
||||
}
|
||||
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return NB.getCurrentBlockCount();
|
||||
}
|
||||
|
||||
const StateTy* GetState(NodeTy* Pred) const {
|
||||
if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
|
||||
return CleanedState;
|
||||
else
|
||||
return Pred->getState();
|
||||
}
|
||||
|
||||
void SetCleanedState(const StateTy* St) {
|
||||
CleanedState = St;
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, const StateTy* St) {
|
||||
return MakeNode(Dst, S, Pred, St, PointKind);
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) {
|
||||
|
||||
const StateTy* PredState = GetState(Pred);
|
||||
|
||||
// If the state hasn't changed, don't generate a new node.
|
||||
if (!BuildSinks && St == PredState && Auditor == 0) {
|
||||
Dst.Add(Pred);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NodeTy* N = generateNode(S, St, Pred, K);
|
||||
|
||||
if (N) {
|
||||
if (BuildSinks)
|
||||
N->markAsSink();
|
||||
else {
|
||||
if (Auditor && Auditor->Audit(N, Mgr))
|
||||
N->markAsSink();
|
||||
|
||||
Dst.Add(N);
|
||||
}
|
||||
}
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
NodeTy* MakeSinkNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, const StateTy* St) {
|
||||
bool Tmp = BuildSinks;
|
||||
BuildSinks = true;
|
||||
NodeTy* N = MakeNode(Dst, S, Pred, St);
|
||||
BuildSinks = Tmp;
|
||||
return N;
|
||||
}
|
||||
|
||||
bool PurgingDeadSymbols;
|
||||
bool BuildSinks;
|
||||
bool HasGeneratedNode;
|
||||
ProgramPoint::Kind PointKind;
|
||||
const void *Tag;
|
||||
};
|
||||
|
||||
class GRBranchNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock* Src;
|
||||
CFGBlock* DstT;
|
||||
CFGBlock* DstF;
|
||||
ExplodedNodeImpl* Pred;
|
||||
|
||||
typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy;
|
||||
DeferredTy Deferred;
|
||||
|
||||
bool GeneratedTrue;
|
||||
bool GeneratedFalse;
|
||||
|
||||
public:
|
||||
GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
|
||||
ExplodedNodeImpl* pred, GRCoreEngineImpl* e)
|
||||
: Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
|
||||
GeneratedTrue(false), GeneratedFalse(false) {}
|
||||
|
||||
~GRBranchNodeBuilderImpl();
|
||||
|
||||
ExplodedNodeImpl* getPredecessor() const { return Pred; }
|
||||
const ExplodedGraphImpl& getGraph() const { return *Eng.G; }
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch);
|
||||
|
||||
CFGBlock* getTargetBlock(bool branch) const {
|
||||
return branch ? DstT : DstF;
|
||||
}
|
||||
|
||||
void markInfeasible(bool branch) {
|
||||
if (branch) GeneratedTrue = true;
|
||||
else GeneratedFalse = true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename STATE>
|
||||
class GRBranchNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
GRBranchNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
const GraphTy& getGraph() const {
|
||||
return static_cast<const GraphTy&>(NB.getGraph());
|
||||
}
|
||||
|
||||
NodeTy* getPredecessor() const {
|
||||
return static_cast<NodeTy*>(NB.getPredecessor());
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return getPredecessor()->getState();
|
||||
}
|
||||
|
||||
NodeTy* generateNode(const StateTy* St, bool branch) {
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
CFGBlock* getTargetBlock(bool branch) const {
|
||||
return NB.getTargetBlock(branch);
|
||||
}
|
||||
|
||||
void markInfeasible(bool branch) {
|
||||
NB.markInfeasible(branch);
|
||||
}
|
||||
};
|
||||
|
||||
class GRIndirectGotoNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock* Src;
|
||||
CFGBlock& DispatchBlock;
|
||||
Expr* E;
|
||||
ExplodedNodeImpl* Pred;
|
||||
public:
|
||||
GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
|
||||
Expr* e, CFGBlock* dispatch,
|
||||
GRCoreEngineImpl* eng)
|
||||
: Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
|
||||
|
||||
|
||||
class Iterator {
|
||||
CFGBlock::succ_iterator I;
|
||||
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
Iterator(CFGBlock::succ_iterator i) : I(i) {}
|
||||
public:
|
||||
|
||||
Iterator& operator++() { ++I; return *this; }
|
||||
bool operator!=(const Iterator& X) const { return I != X.I; }
|
||||
|
||||
LabelStmt* getLabel() const {
|
||||
return llvm::cast<LabelStmt>((*I)->getLabel());
|
||||
}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return *I;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(DispatchBlock.succ_begin()); }
|
||||
Iterator end() { return Iterator(DispatchBlock.succ_end()); }
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State,
|
||||
bool isSink);
|
||||
|
||||
Expr* getTarget() const { return E; }
|
||||
const void* getState() const { return Pred->State; }
|
||||
};
|
||||
|
||||
template<typename STATE>
|
||||
class GRIndirectGotoNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
GRIndirectGotoNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator;
|
||||
|
||||
iterator begin() { return NB.begin(); }
|
||||
iterator end() { return NB.end(); }
|
||||
|
||||
Expr* getTarget() const { return NB.getTarget(); }
|
||||
|
||||
NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return static_cast<const StateTy*>(NB.getState());
|
||||
}
|
||||
};
|
||||
|
||||
class GRSwitchNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock* Src;
|
||||
Expr* Condition;
|
||||
ExplodedNodeImpl* Pred;
|
||||
public:
|
||||
GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
|
||||
Expr* condition, GRCoreEngineImpl* eng)
|
||||
: Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
|
||||
|
||||
class Iterator {
|
||||
CFGBlock::succ_reverse_iterator I;
|
||||
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}
|
||||
public:
|
||||
|
||||
Iterator& operator++() { ++I; return *this; }
|
||||
bool operator!=(const Iterator& X) const { return I != X.I; }
|
||||
|
||||
CaseStmt* getCase() const {
|
||||
return llvm::cast<CaseStmt>((*I)->getLabel());
|
||||
}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return *I;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(Src->succ_rbegin()+1); }
|
||||
Iterator end() { return Iterator(Src->succ_rend()); }
|
||||
|
||||
ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I,
|
||||
const void* State);
|
||||
|
||||
ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State,
|
||||
bool isSink);
|
||||
|
||||
Expr* getCondition() const { return Condition; }
|
||||
const void* getState() const { return Pred->State; }
|
||||
};
|
||||
|
||||
template<typename STATE>
|
||||
class GRSwitchNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
GRSwitchNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
typedef GRSwitchNodeBuilderImpl::Iterator iterator;
|
||||
|
||||
iterator begin() { return NB.begin(); }
|
||||
iterator end() { return NB.end(); }
|
||||
|
||||
Expr* getCondition() const { return NB.getCondition(); }
|
||||
|
||||
NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) {
|
||||
return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
|
||||
}
|
||||
|
||||
NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) {
|
||||
return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return static_cast<const StateTy*>(NB.getState());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class GREndPathNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock& B;
|
||||
ExplodedNodeImpl* Pred;
|
||||
bool HasGeneratedNode;
|
||||
|
||||
public:
|
||||
GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNodeImpl* N,
|
||||
GRCoreEngineImpl* e)
|
||||
: Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
|
||||
|
||||
~GREndPathNodeBuilderImpl();
|
||||
|
||||
ExplodedNodeImpl* getPredecessor() const { return Pred; }
|
||||
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(const void* State,
|
||||
const void *tag = 0,
|
||||
ExplodedNodeImpl *P = 0);
|
||||
|
||||
CFGBlock* getBlock() const { return &B; }
|
||||
};
|
||||
|
||||
|
||||
template<typename STATE>
|
||||
class GREndPathNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
|
||||
GREndPathNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
NodeTy* getPredecessor() const {
|
||||
return static_cast<NodeTy*>(NB.getPredecessor());
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return NB.getCurrentBlockCount();
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return getPredecessor()->getState();
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(const StateTy* St, const void *tag = 0) {
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag));
|
||||
}
|
||||
|
||||
NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) {
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag, Pred));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename SUBENGINE>
|
||||
class GRCoreEngine : public GRCoreEngineImpl {
|
||||
public:
|
||||
typedef SUBENGINE SubEngineTy;
|
||||
typedef typename SubEngineTy::StateTy StateTy;
|
||||
typedef typename StateTy::ManagerTy StateManagerTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
protected:
|
||||
SubEngineTy& SubEngine;
|
||||
|
||||
virtual const void* getInitialState() {
|
||||
return SubEngine.getInitialState();
|
||||
}
|
||||
|
||||
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) {
|
||||
GREndPathNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessEndPath(Builder);
|
||||
}
|
||||
|
||||
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) {
|
||||
GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager());
|
||||
SubEngine.ProcessStmt(S, Builder);
|
||||
}
|
||||
|
||||
virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
|
||||
GRBlockCounter BC) {
|
||||
return SubEngine.ProcessBlockEntrance(Blk,
|
||||
static_cast<const StateTy*>(State),
|
||||
BC);
|
||||
}
|
||||
|
||||
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
|
||||
GRBranchNodeBuilderImpl& BuilderImpl) {
|
||||
GRBranchNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessBranch(Condition, Terminator, Builder);
|
||||
}
|
||||
|
||||
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) {
|
||||
GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessIndirectGoto(Builder);
|
||||
}
|
||||
|
||||
virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
|
||||
GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessSwitch(Builder);
|
||||
}
|
||||
|
||||
public:
|
||||
/// Construct a GRCoreEngine object to analyze the provided CFG using
|
||||
/// a DFS exploration of the exploded graph.
|
||||
GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine)
|
||||
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx),
|
||||
GRWorkList::MakeBFS()),
|
||||
SubEngine(subengine) {}
|
||||
|
||||
/// Construct a GRCoreEngine object to analyze the provided CFG and to
|
||||
/// use the provided worklist object to execute the worklist algorithm.
|
||||
/// The GRCoreEngine object assumes ownership of 'wlist'.
|
||||
GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist,
|
||||
SubEngineTy& subengine)
|
||||
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist),
|
||||
SubEngine(subengine) {}
|
||||
|
||||
virtual ~GRCoreEngine() {}
|
||||
|
||||
/// getGraph - Returns the exploded graph.
|
||||
GraphTy& getGraph() {
|
||||
return *static_cast<GraphTy*>(G.get());
|
||||
}
|
||||
|
||||
/// takeGraph - Returns the exploded graph. Ownership of the graph is
|
||||
/// transfered to the caller.
|
||||
GraphTy* takeGraph() {
|
||||
return static_cast<GraphTy*>(G.take());
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
738
include/clang/Analysis/PathSensitive/GRExprEngine.h
Normal file
738
include/clang/Analysis/PathSensitive/GRExprEngine.h
Normal file
@ -0,0 +1,738 @@
|
||||
//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that
|
||||
// is built on GRCoreEngine, but provides the boilerplate to execute transfer
|
||||
// functions and build the ExplodedGraph at the expression level.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
|
||||
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
|
||||
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PathDiagnosticClient;
|
||||
class Diagnostic;
|
||||
class ObjCForCollectionStmt;
|
||||
|
||||
class GRExprEngine {
|
||||
public:
|
||||
typedef GRState StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef GraphTy::NodeTy NodeTy;
|
||||
|
||||
// Builders.
|
||||
typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder;
|
||||
typedef GRBranchNodeBuilder<StateTy> BranchNodeBuilder;
|
||||
typedef GRIndirectGotoNodeBuilder<StateTy> IndirectGotoNodeBuilder;
|
||||
typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder;
|
||||
typedef GREndPathNodeBuilder<StateTy> EndPathNodeBuilder;
|
||||
typedef ExplodedNodeSet<StateTy> NodeSet;
|
||||
|
||||
protected:
|
||||
GRCoreEngine<GRExprEngine> CoreEngine;
|
||||
|
||||
/// G - the simulation graph.
|
||||
GraphTy& G;
|
||||
|
||||
/// Liveness - live-variables information the ValueDecl* and block-level
|
||||
/// Expr* in the CFG. Used to prune out dead state.
|
||||
LiveVariables& Liveness;
|
||||
|
||||
/// Builder - The current GRStmtNodeBuilder which is used when building the
|
||||
/// nodes for a given statement.
|
||||
StmtNodeBuilder* Builder;
|
||||
|
||||
/// StateMgr - Object that manages the data for all created states.
|
||||
GRStateManager StateMgr;
|
||||
|
||||
/// SymMgr - Object that manages the symbol information.
|
||||
SymbolManager& SymMgr;
|
||||
|
||||
/// ValMgr - Object that manages/creates SVals.
|
||||
ValueManager &ValMgr;
|
||||
|
||||
/// EntryNode - The immediate predecessor node.
|
||||
NodeTy* EntryNode;
|
||||
|
||||
/// CleanedState - The state for EntryNode "cleaned" of all dead
|
||||
/// variables and symbols (as determined by a liveness analysis).
|
||||
const GRState* CleanedState;
|
||||
|
||||
/// CurrentStmt - The current block-level statement.
|
||||
Stmt* CurrentStmt;
|
||||
|
||||
// Obj-C Class Identifiers.
|
||||
IdentifierInfo* NSExceptionII;
|
||||
|
||||
// Obj-C Selectors.
|
||||
Selector* NSExceptionInstanceRaiseSelectors;
|
||||
Selector RaiseSel;
|
||||
|
||||
llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor;
|
||||
|
||||
/// PurgeDead - Remove dead bindings before processing a statement.
|
||||
bool PurgeDead;
|
||||
|
||||
/// BR - The BugReporter associated with this engine. It is important that
|
||||
// this object be placed at the very end of member variables so that its
|
||||
// destructor is called before the rest of the GRExprEngine is destroyed.
|
||||
GRBugReporter BR;
|
||||
|
||||
/// EargerlyAssume - A flag indicating how the engine should handle
|
||||
// expressions such as: 'x = (y != 0)'. When this flag is true then
|
||||
// the subexpression 'y != 0' will be eagerly assumed to be true or false,
|
||||
// thus evaluating it to the integers 0 or 1 respectively. The upside
|
||||
// is that this can increase analysis precision until we have a better way
|
||||
// to lazily evaluate such logic. The downside is that it eagerly
|
||||
// bifurcates paths.
|
||||
const bool EagerlyAssume;
|
||||
|
||||
public:
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> ErrorNodes;
|
||||
typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy;
|
||||
|
||||
/// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted
|
||||
/// from [x ...] with 'x' definitely being nil and the result was a 'struct'
|
||||
// (an undefined value).
|
||||
ErrorNodes NilReceiverStructRetExplicit;
|
||||
|
||||
/// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted
|
||||
/// from [x ...] with 'x' possibly being nil and the result was a 'struct'
|
||||
// (an undefined value).
|
||||
ErrorNodes NilReceiverStructRetImplicit;
|
||||
|
||||
/// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that
|
||||
/// resulted from [x ...] with 'x' definitely being nil and the result's size
|
||||
// was larger than sizeof(void *) (an undefined value).
|
||||
ErrorNodes NilReceiverLargerThanVoidPtrRetExplicit;
|
||||
|
||||
/// NilReceiverLargerThanVoidPtrRetImplicit - Nodes in the ExplodedGraph that
|
||||
/// resulted from [x ...] with 'x' possibly being nil and the result's size
|
||||
// was larger than sizeof(void *) (an undefined value).
|
||||
ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit;
|
||||
|
||||
/// RetsStackAddr - Nodes in the ExplodedGraph that result from returning
|
||||
/// the address of a stack variable.
|
||||
ErrorNodes RetsStackAddr;
|
||||
|
||||
/// RetsUndef - Nodes in the ExplodedGraph that result from returning
|
||||
/// an undefined value.
|
||||
ErrorNodes RetsUndef;
|
||||
|
||||
/// UndefBranches - Nodes in the ExplodedGraph that result from
|
||||
/// taking a branch based on an undefined value.
|
||||
ErrorNodes UndefBranches;
|
||||
|
||||
/// UndefStores - Sinks in the ExplodedGraph that result from
|
||||
/// making a store to an undefined lvalue.
|
||||
ErrorNodes UndefStores;
|
||||
|
||||
/// NoReturnCalls - Sinks in the ExplodedGraph that result from
|
||||
// calling a function with the attribute "noreturn".
|
||||
ErrorNodes NoReturnCalls;
|
||||
|
||||
/// ImplicitNullDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on a symbolic pointer that MAY be NULL.
|
||||
ErrorNodes ImplicitNullDeref;
|
||||
|
||||
/// ExplicitNullDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on a symbolic pointer that MUST be NULL.
|
||||
ErrorNodes ExplicitNullDeref;
|
||||
|
||||
/// UnitDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on an undefined value.
|
||||
ErrorNodes UndefDeref;
|
||||
|
||||
/// ImplicitBadDivides - Nodes in the ExplodedGraph that result from
|
||||
/// evaluating a divide or modulo operation where the denominator
|
||||
/// MAY be zero.
|
||||
ErrorNodes ImplicitBadDivides;
|
||||
|
||||
/// ExplicitBadDivides - Nodes in the ExplodedGraph that result from
|
||||
/// evaluating a divide or modulo operation where the denominator
|
||||
/// MUST be zero or undefined.
|
||||
ErrorNodes ExplicitBadDivides;
|
||||
|
||||
/// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
|
||||
/// constructing a zero-sized VLA where the size may be zero.
|
||||
ErrorNodes ImplicitBadSizedVLA;
|
||||
|
||||
/// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
|
||||
/// constructing a zero-sized VLA where the size must be zero.
|
||||
ErrorNodes ExplicitBadSizedVLA;
|
||||
|
||||
/// UndefResults - Nodes in the ExplodedGraph where the operands are defined
|
||||
/// by the result is not. Excludes divide-by-zero errors.
|
||||
ErrorNodes UndefResults;
|
||||
|
||||
/// BadCalls - Nodes in the ExplodedGraph resulting from calls to function
|
||||
/// pointers that are NULL (or other constants) or Undefined.
|
||||
ErrorNodes BadCalls;
|
||||
|
||||
/// UndefReceiver - Nodes in the ExplodedGraph resulting from message
|
||||
/// ObjC message expressions where the receiver is undefined (uninitialized).
|
||||
ErrorNodes UndefReceivers;
|
||||
|
||||
/// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions
|
||||
/// where a pass-by-value argument has an undefined value.
|
||||
UndefArgsTy UndefArgs;
|
||||
|
||||
/// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from
|
||||
/// message expressions where a pass-by-value argument has an undefined
|
||||
/// value.
|
||||
UndefArgsTy MsgExprUndefArgs;
|
||||
|
||||
/// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from
|
||||
/// out-of-bound memory accesses where the index MAY be out-of-bound.
|
||||
ErrorNodes ImplicitOOBMemAccesses;
|
||||
|
||||
/// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from
|
||||
/// out-of-bound memory accesses where the index MUST be out-of-bound.
|
||||
ErrorNodes ExplicitOOBMemAccesses;
|
||||
|
||||
public:
|
||||
GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L,
|
||||
BugReporterData& BRD,
|
||||
bool purgeDead, bool eagerlyAssume = true,
|
||||
StoreManagerCreator SMC = CreateBasicStoreManager,
|
||||
ConstraintManagerCreator CMC = CreateBasicConstraintManager);
|
||||
|
||||
~GRExprEngine();
|
||||
|
||||
void ExecuteWorkList(unsigned Steps = 150000) {
|
||||
CoreEngine.ExecuteWorkList(Steps);
|
||||
}
|
||||
|
||||
/// getContext - Return the ASTContext associated with this analysis.
|
||||
ASTContext& getContext() const { return G.getContext(); }
|
||||
|
||||
/// getCFG - Returns the CFG associated with this analysis.
|
||||
CFG& getCFG() { return G.getCFG(); }
|
||||
|
||||
GRTransferFuncs& getTF() { return *StateMgr.TF; }
|
||||
|
||||
BugReporter& getBugReporter() { return BR; }
|
||||
|
||||
/// setTransferFunctions
|
||||
void setTransferFunctions(GRTransferFuncs* tf);
|
||||
|
||||
void setTransferFunctions(GRTransferFuncs& tf) {
|
||||
setTransferFunctions(&tf);
|
||||
}
|
||||
|
||||
/// ViewGraph - Visualize the ExplodedGraph created by executing the
|
||||
/// simulation.
|
||||
void ViewGraph(bool trim = false);
|
||||
|
||||
void ViewGraph(NodeTy** Beg, NodeTy** End);
|
||||
|
||||
/// getLiveness - Returned computed live-variables information for the
|
||||
/// analyzed function.
|
||||
const LiveVariables& getLiveness() const { return Liveness; }
|
||||
LiveVariables& getLiveness() { return Liveness; }
|
||||
|
||||
/// getInitialState - Return the initial state used for the root vertex
|
||||
/// in the ExplodedGraph.
|
||||
const GRState* getInitialState();
|
||||
|
||||
GraphTy& getGraph() { return G; }
|
||||
const GraphTy& getGraph() const { return G; }
|
||||
|
||||
void RegisterInternalChecks();
|
||||
|
||||
bool isRetStackAddr(const NodeTy* N) const {
|
||||
return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefControlFlow(const NodeTy* N) const {
|
||||
return N->isSink() && UndefBranches.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefStore(const NodeTy* N) const {
|
||||
return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isImplicitNullDeref(const NodeTy* N) const {
|
||||
return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isExplicitNullDeref(const NodeTy* N) const {
|
||||
return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefDeref(const NodeTy* N) const {
|
||||
return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isImplicitBadDivide(const NodeTy* N) const {
|
||||
return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isExplicitBadDivide(const NodeTy* N) const {
|
||||
return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isNoReturnCall(const NodeTy* N) const {
|
||||
return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefResult(const NodeTy* N) const {
|
||||
return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isBadCall(const NodeTy* N) const {
|
||||
return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefArg(const NodeTy* N) const {
|
||||
return N->isSink() &&
|
||||
(UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() ||
|
||||
MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end());
|
||||
}
|
||||
|
||||
bool isUndefReceiver(const NodeTy* N) const {
|
||||
return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator ret_stackaddr_iterator;
|
||||
ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); }
|
||||
ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator ret_undef_iterator;
|
||||
ret_undef_iterator ret_undef_begin() { return RetsUndef.begin(); }
|
||||
ret_undef_iterator ret_undef_end() { return RetsUndef.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator undef_branch_iterator;
|
||||
undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); }
|
||||
undef_branch_iterator undef_branches_end() { return UndefBranches.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator null_deref_iterator;
|
||||
null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); }
|
||||
null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); }
|
||||
|
||||
null_deref_iterator implicit_null_derefs_begin() {
|
||||
return ImplicitNullDeref.begin();
|
||||
}
|
||||
null_deref_iterator implicit_null_derefs_end() {
|
||||
return ImplicitNullDeref.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator;
|
||||
|
||||
nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() {
|
||||
return NilReceiverStructRetExplicit.begin();
|
||||
}
|
||||
|
||||
nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() {
|
||||
return NilReceiverStructRetExplicit.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator;
|
||||
|
||||
nil_receiver_larger_than_voidptr_ret_iterator
|
||||
nil_receiver_larger_than_voidptr_ret_begin() {
|
||||
return NilReceiverLargerThanVoidPtrRetExplicit.begin();
|
||||
}
|
||||
|
||||
nil_receiver_larger_than_voidptr_ret_iterator
|
||||
nil_receiver_larger_than_voidptr_ret_end() {
|
||||
return NilReceiverLargerThanVoidPtrRetExplicit.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator undef_deref_iterator;
|
||||
undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); }
|
||||
undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator bad_divide_iterator;
|
||||
|
||||
bad_divide_iterator explicit_bad_divides_begin() {
|
||||
return ExplicitBadDivides.begin();
|
||||
}
|
||||
|
||||
bad_divide_iterator explicit_bad_divides_end() {
|
||||
return ExplicitBadDivides.end();
|
||||
}
|
||||
|
||||
bad_divide_iterator implicit_bad_divides_begin() {
|
||||
return ImplicitBadDivides.begin();
|
||||
}
|
||||
|
||||
bad_divide_iterator implicit_bad_divides_end() {
|
||||
return ImplicitBadDivides.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator undef_result_iterator;
|
||||
undef_result_iterator undef_results_begin() { return UndefResults.begin(); }
|
||||
undef_result_iterator undef_results_end() { return UndefResults.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator bad_calls_iterator;
|
||||
bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); }
|
||||
bad_calls_iterator bad_calls_end() { return BadCalls.end(); }
|
||||
|
||||
typedef UndefArgsTy::iterator undef_arg_iterator;
|
||||
undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); }
|
||||
undef_arg_iterator undef_arg_end() { return UndefArgs.end(); }
|
||||
|
||||
undef_arg_iterator msg_expr_undef_arg_begin() {
|
||||
return MsgExprUndefArgs.begin();
|
||||
}
|
||||
undef_arg_iterator msg_expr_undef_arg_end() {
|
||||
return MsgExprUndefArgs.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator undef_receivers_iterator;
|
||||
|
||||
undef_receivers_iterator undef_receivers_begin() {
|
||||
return UndefReceivers.begin();
|
||||
}
|
||||
|
||||
undef_receivers_iterator undef_receivers_end() {
|
||||
return UndefReceivers.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator oob_memacc_iterator;
|
||||
oob_memacc_iterator implicit_oob_memacc_begin() {
|
||||
return ImplicitOOBMemAccesses.begin();
|
||||
}
|
||||
oob_memacc_iterator implicit_oob_memacc_end() {
|
||||
return ImplicitOOBMemAccesses.end();
|
||||
}
|
||||
oob_memacc_iterator explicit_oob_memacc_begin() {
|
||||
return ExplicitOOBMemAccesses.begin();
|
||||
}
|
||||
oob_memacc_iterator explicit_oob_memacc_end() {
|
||||
return ExplicitOOBMemAccesses.end();
|
||||
}
|
||||
|
||||
void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C);
|
||||
void AddCheck(GRSimpleAPICheck* A);
|
||||
|
||||
/// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
|
||||
/// nodes by processing the 'effects' of a block-level statement.
|
||||
void ProcessStmt(Stmt* S, StmtNodeBuilder& builder);
|
||||
|
||||
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
|
||||
/// a CFGBlock. This method returns true if the analysis should continue
|
||||
/// exploring the given path, and false otherwise.
|
||||
bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
|
||||
GRBlockCounter BC);
|
||||
|
||||
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
|
||||
/// nodes by processing the 'effects' of a branch condition.
|
||||
void ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder);
|
||||
|
||||
/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
|
||||
/// nodes by processing the 'effects' of a computed goto jump.
|
||||
void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder);
|
||||
|
||||
/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
|
||||
/// nodes by processing the 'effects' of a switch statement.
|
||||
void ProcessSwitch(SwitchNodeBuilder& builder);
|
||||
|
||||
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
|
||||
/// nodes when the control reaches the end of a function.
|
||||
void ProcessEndPath(EndPathNodeBuilder& builder) {
|
||||
getTF().EvalEndPath(*this, builder);
|
||||
StateMgr.EndPath(builder.getState());
|
||||
}
|
||||
|
||||
GRStateManager& getStateManager() { return StateMgr; }
|
||||
const GRStateManager& getStateManager() const { return StateMgr; }
|
||||
|
||||
StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
|
||||
|
||||
ConstraintManager& getConstraintManager() {
|
||||
return StateMgr.getConstraintManager();
|
||||
}
|
||||
|
||||
// FIXME: Remove when we migrate over to just using ValueManager.
|
||||
BasicValueFactory& getBasicVals() {
|
||||
return StateMgr.getBasicVals();
|
||||
}
|
||||
const BasicValueFactory& getBasicVals() const {
|
||||
return StateMgr.getBasicVals();
|
||||
}
|
||||
|
||||
ValueManager &getValueManager() { return ValMgr; }
|
||||
const ValueManager &getValueManager() const { return ValMgr; }
|
||||
|
||||
// FIXME: Remove when we migrate over to just using ValueManager.
|
||||
SymbolManager& getSymbolManager() { return SymMgr; }
|
||||
const SymbolManager& getSymbolManager() const { return SymMgr; }
|
||||
|
||||
protected:
|
||||
|
||||
const GRState* GetState(NodeTy* N) {
|
||||
return N == EntryNode ? CleanedState : N->getState();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
const GRState* BindExpr(const GRState* St, Expr* Ex, SVal V) {
|
||||
return StateMgr.BindExpr(St, Ex, V);
|
||||
}
|
||||
|
||||
const GRState* BindExpr(const GRState* St, const Expr* Ex, SVal V) {
|
||||
return BindExpr(St, const_cast<Expr*>(Ex), V);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
const GRState* BindBlkExpr(const GRState* St, Expr* Ex, SVal V) {
|
||||
return StateMgr.BindExpr(St, Ex, V, true, false);
|
||||
}
|
||||
|
||||
const GRState* BindLoc(const GRState* St, Loc LV, SVal V) {
|
||||
return StateMgr.BindLoc(St, LV, V);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* St, Stmt* Ex) {
|
||||
return StateMgr.GetSVal(St, Ex);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* St, const Stmt* Ex) {
|
||||
return GetSVal(St, const_cast<Stmt*>(Ex));
|
||||
}
|
||||
|
||||
SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) {
|
||||
return StateMgr.GetBlkExprSVal(St, Ex);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* St, Loc LV, QualType T = QualType()) {
|
||||
return StateMgr.GetSVal(St, LV, T);
|
||||
}
|
||||
|
||||
inline NonLoc MakeConstantVal(uint64_t X, Expr* Ex) {
|
||||
return NonLoc::MakeVal(getBasicVals(), X, Ex->getType());
|
||||
}
|
||||
|
||||
/// Assume - Create new state by assuming that a given expression
|
||||
/// is true or false.
|
||||
const GRState* Assume(const GRState* St, SVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return StateMgr.Assume(St, Cond, Assumption, isFeasible);
|
||||
}
|
||||
|
||||
const GRState* Assume(const GRState* St, Loc Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return StateMgr.Assume(St, Cond, Assumption, isFeasible);
|
||||
}
|
||||
|
||||
const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound,
|
||||
bool Assumption, bool& isFeasible) {
|
||||
return StateMgr.AssumeInBound(St, Idx, UpperBound, Assumption, isFeasible);
|
||||
}
|
||||
|
||||
public:
|
||||
NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
|
||||
const void *tag = 0);
|
||||
protected:
|
||||
|
||||
/// Visit - Transfer function logic for all statements. Dispatches to
|
||||
/// other functions that handle specific kinds of statements.
|
||||
void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is
|
||||
/// a DeclRefExpr, it evaluates to the MemRegionVal which represents its
|
||||
/// storage location. Note that not all kinds of expressions has lvalue.
|
||||
void VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitArraySubscriptExpr - Transfer function for array accesses.
|
||||
void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst, bool asLValue);
|
||||
|
||||
/// VisitAsmStmt - Transfer function logic for inline asm.
|
||||
void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitAsmStmtHelperOutputs(AsmStmt* A,
|
||||
AsmStmt::outputs_iterator I,
|
||||
AsmStmt::outputs_iterator E,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitAsmStmtHelperInputs(AsmStmt* A,
|
||||
AsmStmt::inputs_iterator I,
|
||||
AsmStmt::inputs_iterator E,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitBinaryOperator - Transfer function logic for binary operators.
|
||||
void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
|
||||
/// VisitCall - Transfer function for function calls.
|
||||
void VisitCall(CallExpr* CE, NodeTy* Pred,
|
||||
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
|
||||
NodeSet& Dst);
|
||||
void VisitCallRec(CallExpr* CE, NodeTy* Pred,
|
||||
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
|
||||
NodeSet& Dst, const FunctionProtoType *,
|
||||
unsigned ParamIdx = 0);
|
||||
|
||||
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
|
||||
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitCastPointerToInteger - Transfer function (called by VisitCast) that
|
||||
/// handles pointer to integer casts and array to integer casts.
|
||||
void VisitCastPointerToInteger(SVal V, const GRState* state, QualType PtrTy,
|
||||
Expr* CastE, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
|
||||
void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, NodeTy* Pred,
|
||||
NodeSet& Dst, bool asLValue);
|
||||
|
||||
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLValue);
|
||||
|
||||
/// VisitDeclStmt - Transfer function logic for DeclStmts.
|
||||
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
|
||||
void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitInitListExpr(InitListExpr* E, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
|
||||
void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitMemberExpr - Transfer function for member expressions.
|
||||
void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue);
|
||||
|
||||
/// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs.
|
||||
void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLValue);
|
||||
|
||||
/// VisitObjCForCollectionStmt - Transfer function logic for
|
||||
/// ObjCForCollectionStmt.
|
||||
void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, NodeTy* Pred,
|
||||
NodeSet& Dst, SVal ElementV);
|
||||
|
||||
/// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
|
||||
void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
|
||||
ObjCMessageExpr::arg_iterator I,
|
||||
ObjCMessageExpr::arg_iterator E,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
/// VisitReturnStmt - Transfer function logic for return statements.
|
||||
void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
|
||||
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
/// VisitUnaryOperator - Transfer function logic for unary operators.
|
||||
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLValue);
|
||||
|
||||
const GRState* CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred,
|
||||
SVal Denom);
|
||||
|
||||
/// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
|
||||
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
|
||||
/// with those assumptions.
|
||||
void EvalEagerlyAssume(NodeSet& Dst, NodeSet& Src, Expr *Ex);
|
||||
|
||||
SVal EvalCast(SVal X, QualType CastT) {
|
||||
if (X.isUnknownOrUndef())
|
||||
return X;
|
||||
|
||||
if (isa<Loc>(X))
|
||||
return getTF().EvalCast(*this, cast<Loc>(X), CastT);
|
||||
else
|
||||
return getTF().EvalCast(*this, cast<NonLoc>(X), CastT);
|
||||
}
|
||||
|
||||
SVal EvalMinus(UnaryOperator* U, SVal X) {
|
||||
return X.isValid() ? getTF().EvalMinus(*this, U, cast<NonLoc>(X)) : X;
|
||||
}
|
||||
|
||||
SVal EvalComplement(SVal X) {
|
||||
return X.isValid() ? getTF().EvalComplement(*this, cast<NonLoc>(X)) : X;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T) {
|
||||
return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, R, T)
|
||||
: R;
|
||||
}
|
||||
|
||||
SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, SVal R, QualType T) {
|
||||
return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L,
|
||||
cast<NonLoc>(R), T) : R;
|
||||
}
|
||||
|
||||
void EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLoc L, NonLoc R,
|
||||
ExplodedNode<GRState>* Pred, QualType T);
|
||||
|
||||
void EvalBinOp(GRStateSet& OStates, const GRState* St, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T);
|
||||
|
||||
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, SVal L,SVal R,
|
||||
QualType T);
|
||||
|
||||
protected:
|
||||
|
||||
void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred);
|
||||
|
||||
void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
|
||||
}
|
||||
|
||||
void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
|
||||
|
||||
const GRState* MarkBranch(const GRState* St, Stmt* Terminator,
|
||||
bool branchTaken);
|
||||
|
||||
/// EvalBind - Handle the semantics of binding a value to a specific location.
|
||||
/// This method is used by EvalStore, VisitDeclStmt, and others.
|
||||
void EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
|
||||
const GRState* St, SVal location, SVal Val);
|
||||
|
||||
public:
|
||||
void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
|
||||
const GRState* St, SVal location, const void *tag = 0);
|
||||
|
||||
NodeTy* EvalLocation(Stmt* Ex, NodeTy* Pred,
|
||||
const GRState* St, SVal location,
|
||||
const void *tag = 0);
|
||||
|
||||
|
||||
void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St,
|
||||
SVal TargetLV, SVal Val, const void *tag = 0);
|
||||
|
||||
void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred,
|
||||
const GRState* St, SVal TargetLV, SVal Val,
|
||||
const void *tag = 0);
|
||||
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
101
include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h
Normal file
101
include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h
Normal file
@ -0,0 +1,101 @@
|
||||
//===-- GRExprEngineBuilders.h - "Builder" classes for GRExprEngine -*- 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 smart builder "references" which are used to marshal
|
||||
// builders between GRExprEngine objects and their related components.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
|
||||
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
// SaveAndRestore - A utility class that uses RAII to save and restore
|
||||
// the value of a variable.
|
||||
template<typename T>
|
||||
struct SaveAndRestore {
|
||||
SaveAndRestore(T& x) : X(x), old_value(x) {}
|
||||
~SaveAndRestore() { X = old_value; }
|
||||
T get() { return old_value; }
|
||||
private:
|
||||
T& X;
|
||||
T old_value;
|
||||
};
|
||||
|
||||
// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old
|
||||
// value of a variable is saved, and during the dstor the old value is
|
||||
// or'ed with the new value.
|
||||
struct SaveOr {
|
||||
SaveOr(bool& x) : X(x), old_value(x) { x = false; }
|
||||
~SaveOr() { X |= old_value; }
|
||||
private:
|
||||
bool& X;
|
||||
const bool old_value;
|
||||
};
|
||||
|
||||
class GRStmtNodeBuilderRef {
|
||||
GRExprEngine::NodeSet &Dst;
|
||||
GRExprEngine::StmtNodeBuilder &B;
|
||||
GRExprEngine& Eng;
|
||||
GRExprEngine::NodeTy* Pred;
|
||||
const GRState* state;
|
||||
const Stmt* stmt;
|
||||
const unsigned OldSize;
|
||||
const bool AutoCreateNode;
|
||||
SaveAndRestore<bool> OldSink;
|
||||
SaveAndRestore<const void*> OldTag;
|
||||
SaveOr OldHasGen;
|
||||
|
||||
private:
|
||||
friend class GRExprEngine;
|
||||
|
||||
GRStmtNodeBuilderRef(); // do not implement
|
||||
void operator=(const GRStmtNodeBuilderRef&); // do not implement
|
||||
|
||||
GRStmtNodeBuilderRef(GRExprEngine::NodeSet &dst,
|
||||
GRExprEngine::StmtNodeBuilder &builder,
|
||||
GRExprEngine& eng,
|
||||
GRExprEngine::NodeTy* pred,
|
||||
const GRState *st,
|
||||
const Stmt* s, bool auto_create_node)
|
||||
: Dst(dst), B(builder), Eng(eng), Pred(pred),
|
||||
state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node),
|
||||
OldSink(B.BuildSinks), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {}
|
||||
|
||||
public:
|
||||
|
||||
~GRStmtNodeBuilderRef() {
|
||||
// Handle the case where no nodes where generated. Auto-generate that
|
||||
// contains the updated state if we aren't generating sinks.
|
||||
if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) {
|
||||
if (AutoCreateNode)
|
||||
B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
|
||||
else
|
||||
Dst.Add(Pred);
|
||||
}
|
||||
}
|
||||
|
||||
GRStateRef getState() {
|
||||
return GRStateRef(state, Eng.getStateManager());
|
||||
}
|
||||
|
||||
GRStateManager& getStateManager() {
|
||||
return Eng.getStateManager();
|
||||
}
|
||||
|
||||
GRExprEngine::NodeTy* MakeNode(const GRState* state) {
|
||||
return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
40
include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
Normal file
40
include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
Normal file
@ -0,0 +1,40 @@
|
||||
// GRCheckAPI.h - Simple API checks based on GRAuditor ------------*- 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 interface for building simple, path-sensitive checks
|
||||
// that are stateless and only emit warnings at errors that occur at
|
||||
// CallExpr or ObjCMessageExpr.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS
|
||||
#define LLVM_CLANG_ANALYSIS_GRAPICHECKS
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GRAuditor.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Diagnostic;
|
||||
class BugReporter;
|
||||
class ASTContext;
|
||||
class GRExprEngine;
|
||||
class PathDiagnosticClient;
|
||||
template <typename T> class ExplodedGraph;
|
||||
|
||||
|
||||
class GRSimpleAPICheck : public GRAuditor<GRState> {
|
||||
public:
|
||||
GRSimpleAPICheck() {}
|
||||
virtual ~GRSimpleAPICheck() {}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
820
include/clang/Analysis/PathSensitive/GRState.h
Normal file
820
include/clang/Analysis/PathSensitive/GRState.h
Normal file
@ -0,0 +1,820 @@
|
||||
//== GRState*h - Path-Sens. "State" for tracking valuues -----*- 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 SymbolRef, ExprBindKey, and GRState*
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H
|
||||
#define LLVM_CLANG_ANALYSIS_VALUESTATE_H
|
||||
|
||||
// FIXME: Reduce the number of includes.
|
||||
|
||||
#include "clang/Analysis/PathSensitive/Environment.h"
|
||||
#include "clang/Analysis/PathSensitive/Store.h"
|
||||
#include "clang/Analysis/PathSensitive/ConstraintManager.h"
|
||||
#include "clang/Analysis/PathSensitive/ValueManager.h"
|
||||
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRStateManager;
|
||||
class GRTransferFuncs;
|
||||
|
||||
typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&);
|
||||
typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRStateTrait - Traits used by the Generic Data Map of a GRState.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T> struct GRStatePartialTrait;
|
||||
|
||||
template <typename T> struct GRStateTrait {
|
||||
typedef typename T::data_type data_type;
|
||||
static inline void* GDMIndex() { return &T::TagInt; }
|
||||
static inline void* MakeVoidPtr(data_type D) { return (void*) D; }
|
||||
static inline data_type MakeData(void* const* P) {
|
||||
return P ? (data_type) *P : (data_type) 0;
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRState- An ImmutableMap type Stmt*/Decl*/Symbols to SVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// GRState - This class encapsulates the actual data values for
|
||||
/// for a "state" in our symbolic value tracking. It is intended to be
|
||||
/// used as a functional object; that is once it is created and made
|
||||
/// "persistent" in a FoldingSet its values will never change.
|
||||
class GRState : public llvm::FoldingSetNode {
|
||||
public:
|
||||
// Typedefs.
|
||||
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
|
||||
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
|
||||
|
||||
typedef GRStateManager ManagerTy;
|
||||
|
||||
private:
|
||||
void operator=(const GRState& R) const;
|
||||
|
||||
friend class GRStateManager;
|
||||
|
||||
Environment Env;
|
||||
Store St;
|
||||
|
||||
// FIXME: Make these private.
|
||||
public:
|
||||
GenericDataMap GDM;
|
||||
|
||||
public:
|
||||
|
||||
/// This ctor is used when creating the first GRState object.
|
||||
GRState(const Environment& env, Store st, GenericDataMap gdm)
|
||||
: Env(env),
|
||||
St(st),
|
||||
GDM(gdm) {}
|
||||
|
||||
/// Copy ctor - We must explicitly define this or else the "Next" ptr
|
||||
/// in FoldingSetNode will also get copied.
|
||||
GRState(const GRState& RHS)
|
||||
: llvm::FoldingSetNode(),
|
||||
Env(RHS.Env),
|
||||
St(RHS.St),
|
||||
GDM(RHS.GDM) {}
|
||||
|
||||
/// getEnvironment - Return the environment associated with this state.
|
||||
/// The environment is the mapping from expressions to values.
|
||||
const Environment& getEnvironment() const { return Env; }
|
||||
|
||||
/// getStore - Return the store associated with this state. The store
|
||||
/// is a mapping from locations to values.
|
||||
Store getStore() const { return St; }
|
||||
|
||||
/// getGDM - Return the generic data map associated with this state.
|
||||
GenericDataMap getGDM() const { return GDM; }
|
||||
|
||||
/// Profile - Profile the contents of a GRState object for use
|
||||
/// in a FoldingSet.
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) {
|
||||
V->Env.Profile(ID);
|
||||
ID.AddPointer(V->St);
|
||||
V->GDM.Profile(ID);
|
||||
}
|
||||
|
||||
/// Profile - Used to profile the contents of this object for inclusion
|
||||
/// in a FoldingSet.
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
Profile(ID, this);
|
||||
}
|
||||
|
||||
SVal LookupExpr(Expr* E) const {
|
||||
return Env.LookupExpr(E);
|
||||
}
|
||||
|
||||
// Iterators.
|
||||
typedef Environment::seb_iterator seb_iterator;
|
||||
seb_iterator seb_begin() const { return Env.seb_begin(); }
|
||||
seb_iterator seb_end() const { return Env.beb_end(); }
|
||||
|
||||
typedef Environment::beb_iterator beb_iterator;
|
||||
beb_iterator beb_begin() const { return Env.beb_begin(); }
|
||||
beb_iterator beb_end() const { return Env.beb_end(); }
|
||||
|
||||
// Trait based GDM dispatch.
|
||||
void* const* FindGDM(void* K) const;
|
||||
|
||||
template <typename T>
|
||||
typename GRStateTrait<T>::data_type
|
||||
get() const {
|
||||
return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename GRStateTrait<T>::lookup_type
|
||||
get(typename GRStateTrait<T>::key_type key) const {
|
||||
void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
|
||||
return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool contains(typename GRStateTrait<T>::key_type key) const {
|
||||
void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
|
||||
return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key);
|
||||
}
|
||||
|
||||
// State pretty-printing.
|
||||
class Printer {
|
||||
public:
|
||||
virtual ~Printer() {}
|
||||
virtual void Print(std::ostream& Out, const GRState* state,
|
||||
const char* nl, const char* sep) = 0;
|
||||
};
|
||||
|
||||
void print(std::ostream& Out, StoreManager& StoreMgr,
|
||||
ConstraintManager& ConstraintMgr,
|
||||
Printer **Beg = 0, Printer **End = 0,
|
||||
const char* nl = "\n", const char *sep = "") const;
|
||||
|
||||
// Tags used for the Generic Data Map.
|
||||
struct NullDerefTag {
|
||||
static int TagInt;
|
||||
typedef const SVal* data_type;
|
||||
};
|
||||
};
|
||||
|
||||
template<> struct GRTrait<GRState*> {
|
||||
static inline void* toPtr(GRState* St) { return (void*) St; }
|
||||
static inline GRState* toState(void* P) { return (GRState*) P; }
|
||||
static inline void Profile(llvm::FoldingSetNodeID& profile, GRState* St) {
|
||||
// At this point states have already been uniqued. Just
|
||||
// add the pointer.
|
||||
profile.AddPointer(St);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class GRStateSet {
|
||||
typedef llvm::SmallPtrSet<const GRState*,5> ImplTy;
|
||||
ImplTy Impl;
|
||||
public:
|
||||
GRStateSet() {}
|
||||
|
||||
inline void Add(const GRState* St) {
|
||||
Impl.insert(St);
|
||||
}
|
||||
|
||||
typedef ImplTy::const_iterator iterator;
|
||||
|
||||
inline unsigned size() const { return Impl.size(); }
|
||||
inline bool empty() const { return Impl.empty(); }
|
||||
|
||||
inline iterator begin() const { return Impl.begin(); }
|
||||
inline iterator end() const { return Impl.end(); }
|
||||
|
||||
class AutoPopulate {
|
||||
GRStateSet& S;
|
||||
unsigned StartSize;
|
||||
const GRState* St;
|
||||
public:
|
||||
AutoPopulate(GRStateSet& s, const GRState* st)
|
||||
: S(s), StartSize(S.size()), St(st) {}
|
||||
|
||||
~AutoPopulate() {
|
||||
if (StartSize == S.size())
|
||||
S.Add(St);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRStateManager - Factory object for GRStates.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class GRStateRef;
|
||||
|
||||
class GRStateManager {
|
||||
friend class GRExprEngine;
|
||||
friend class GRStateRef;
|
||||
|
||||
private:
|
||||
EnvironmentManager EnvMgr;
|
||||
llvm::OwningPtr<StoreManager> StoreMgr;
|
||||
llvm::OwningPtr<ConstraintManager> ConstraintMgr;
|
||||
GRState::IntSetTy::Factory ISetFactory;
|
||||
|
||||
GRState::GenericDataMap::Factory GDMFactory;
|
||||
|
||||
typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
|
||||
GDMContextsTy GDMContexts;
|
||||
|
||||
/// Printers - A set of printer objects used for pretty-printing a GRState.
|
||||
/// GRStateManager owns these objects.
|
||||
std::vector<GRState::Printer*> Printers;
|
||||
|
||||
/// StateSet - FoldingSet containing all the states created for analyzing
|
||||
/// a particular function. This is used to unique states.
|
||||
llvm::FoldingSet<GRState> StateSet;
|
||||
|
||||
/// ValueMgr - Object that manages the data for all created SVals.
|
||||
ValueManager ValueMgr;
|
||||
|
||||
/// Alloc - A BumpPtrAllocator to allocate states.
|
||||
llvm::BumpPtrAllocator& Alloc;
|
||||
|
||||
/// CurrentStmt - The block-level statement currently being visited. This
|
||||
/// is set by GRExprEngine.
|
||||
Stmt* CurrentStmt;
|
||||
|
||||
/// cfg - The CFG for the analyzed function/method.
|
||||
CFG& cfg;
|
||||
|
||||
/// codedecl - The Decl representing the function/method being analyzed.
|
||||
const Decl& codedecl;
|
||||
|
||||
/// TF - Object that represents a bundle of transfer functions
|
||||
/// for manipulating and creating SVals.
|
||||
GRTransferFuncs* TF;
|
||||
|
||||
/// Liveness - live-variables information of the ValueDecl* and block-level
|
||||
/// Expr* in the CFG. Used to get initial store and prune out dead state.
|
||||
LiveVariables& Liveness;
|
||||
|
||||
private:
|
||||
|
||||
Environment RemoveBlkExpr(const Environment& Env, Expr* E) {
|
||||
return EnvMgr.RemoveBlkExpr(Env, E);
|
||||
}
|
||||
|
||||
// FIXME: Remove when we do lazy initializaton of variable bindings.
|
||||
// const GRState* BindVar(const GRState* St, VarDecl* D, SVal V) {
|
||||
// return SetSVal(St, getLoc(D), V);
|
||||
// }
|
||||
|
||||
public:
|
||||
|
||||
GRStateManager(ASTContext& Ctx,
|
||||
StoreManagerCreator CreateStoreManager,
|
||||
ConstraintManagerCreator CreateConstraintManager,
|
||||
llvm::BumpPtrAllocator& alloc, CFG& c,
|
||||
const Decl& cd, LiveVariables& L)
|
||||
: EnvMgr(alloc),
|
||||
ISetFactory(alloc),
|
||||
GDMFactory(alloc),
|
||||
ValueMgr(alloc, Ctx),
|
||||
Alloc(alloc),
|
||||
cfg(c),
|
||||
codedecl(cd),
|
||||
Liveness(L) {
|
||||
StoreMgr.reset((*CreateStoreManager)(*this));
|
||||
ConstraintMgr.reset((*CreateConstraintManager)(*this));
|
||||
}
|
||||
|
||||
~GRStateManager();
|
||||
|
||||
const GRState* getInitialState();
|
||||
|
||||
ASTContext &getContext() { return ValueMgr.getContext(); }
|
||||
const ASTContext &getContext() const { return ValueMgr.getContext(); }
|
||||
|
||||
const Decl &getCodeDecl() { return codedecl; }
|
||||
GRTransferFuncs& getTransferFuncs() { return *TF; }
|
||||
|
||||
BasicValueFactory &getBasicVals() {
|
||||
return ValueMgr.getBasicValueFactory();
|
||||
}
|
||||
const BasicValueFactory& getBasicVals() const {
|
||||
return ValueMgr.getBasicValueFactory();
|
||||
}
|
||||
|
||||
SymbolManager &getSymbolManager() {
|
||||
return ValueMgr.getSymbolManager();
|
||||
}
|
||||
const SymbolManager &getSymbolManager() const {
|
||||
return ValueMgr.getSymbolManager();
|
||||
}
|
||||
|
||||
ValueManager &getValueManager() { return ValueMgr; }
|
||||
const ValueManager &getValueManager() const { return ValueMgr; }
|
||||
|
||||
LiveVariables& getLiveVariables() { return Liveness; }
|
||||
llvm::BumpPtrAllocator& getAllocator() { return Alloc; }
|
||||
|
||||
MemRegionManager& getRegionManager() {
|
||||
return ValueMgr.getRegionManager();
|
||||
}
|
||||
const MemRegionManager& getRegionManager() const {
|
||||
return ValueMgr.getRegionManager();
|
||||
}
|
||||
|
||||
StoreManager& getStoreManager() { return *StoreMgr; }
|
||||
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
|
||||
|
||||
const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal IVal) {
|
||||
// Store manager should return a persistent state.
|
||||
return StoreMgr->BindDecl(St, VD, IVal);
|
||||
}
|
||||
|
||||
const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) {
|
||||
// Store manager should return a persistent state.
|
||||
return StoreMgr->BindDeclWithNoInit(St, VD);
|
||||
}
|
||||
|
||||
/// BindCompoundLiteral - Return the state that has the bindings currently
|
||||
/// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region
|
||||
/// for the compound literal and 'BegInit' and 'EndInit' represent an
|
||||
/// array of initializer values.
|
||||
const GRState* BindCompoundLiteral(const GRState* St,
|
||||
const CompoundLiteralExpr* CL, SVal V) {
|
||||
return StoreMgr->BindCompoundLiteral(St, CL, V);
|
||||
}
|
||||
|
||||
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
|
||||
SymbolReaper& SymReaper);
|
||||
|
||||
const GRState* RemoveSubExprBindings(const GRState* St) {
|
||||
GRState NewSt = *St;
|
||||
NewSt.Env = EnvMgr.RemoveSubExprBindings(NewSt.Env);
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
|
||||
// Utility methods for getting regions.
|
||||
|
||||
VarRegion* getRegion(const VarDecl* D) {
|
||||
return getRegionManager().getVarRegion(D);
|
||||
}
|
||||
|
||||
const MemRegion* getSelfRegion(const GRState* state) {
|
||||
return StoreMgr->getSelfRegion(state->getStore());
|
||||
}
|
||||
|
||||
// Get the lvalue for a variable reference.
|
||||
SVal GetLValue(const GRState* St, const VarDecl* D) {
|
||||
return StoreMgr->getLValueVar(St, D);
|
||||
}
|
||||
|
||||
// Get the lvalue for a StringLiteral.
|
||||
SVal GetLValue(const GRState* St, const StringLiteral* E) {
|
||||
return StoreMgr->getLValueString(St, E);
|
||||
}
|
||||
|
||||
SVal GetLValue(const GRState* St, const CompoundLiteralExpr* CL) {
|
||||
return StoreMgr->getLValueCompoundLiteral(St, CL);
|
||||
}
|
||||
|
||||
// Get the lvalue for an ivar reference.
|
||||
SVal GetLValue(const GRState* St, const ObjCIvarDecl* D, SVal Base) {
|
||||
return StoreMgr->getLValueIvar(St, D, Base);
|
||||
}
|
||||
|
||||
// Get the lvalue for a field reference.
|
||||
SVal GetLValue(const GRState* St, SVal Base, const FieldDecl* D) {
|
||||
return StoreMgr->getLValueField(St, Base, D);
|
||||
}
|
||||
|
||||
// Get the lvalue for an array index.
|
||||
SVal GetLValue(const GRState* St, QualType ElementType, SVal Base, SVal Idx) {
|
||||
return StoreMgr->getLValueElement(St, ElementType, Base, Idx);
|
||||
}
|
||||
|
||||
// Methods that query & manipulate the Environment.
|
||||
|
||||
SVal GetSVal(const GRState* St, Stmt* Ex) {
|
||||
return St->getEnvironment().GetSVal(Ex, getBasicVals());
|
||||
}
|
||||
|
||||
SVal GetSValAsScalarOrLoc(const GRState* state, const Stmt *S) {
|
||||
if (const Expr *Ex = dyn_cast<Expr>(S)) {
|
||||
QualType T = Ex->getType();
|
||||
if (Loc::IsLocType(T) || T->isIntegerType())
|
||||
return GetSVal(state, S);
|
||||
}
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
|
||||
SVal GetSVal(const GRState* St, const Stmt* Ex) {
|
||||
return St->getEnvironment().GetSVal(const_cast<Stmt*>(Ex), getBasicVals());
|
||||
}
|
||||
|
||||
SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) {
|
||||
return St->getEnvironment().GetBlkExprSVal(Ex, getBasicVals());
|
||||
}
|
||||
|
||||
|
||||
|
||||
const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V,
|
||||
bool isBlkExpr, bool Invalidate) {
|
||||
|
||||
const Environment& OldEnv = St->getEnvironment();
|
||||
Environment NewEnv = EnvMgr.BindExpr(OldEnv, Ex, V, isBlkExpr, Invalidate);
|
||||
|
||||
if (NewEnv == OldEnv)
|
||||
return St;
|
||||
|
||||
GRState NewSt = *St;
|
||||
NewSt.Env = NewEnv;
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V,
|
||||
bool Invalidate = true) {
|
||||
|
||||
bool isBlkExpr = false;
|
||||
|
||||
if (Ex == CurrentStmt) {
|
||||
// FIXME: Should this just be an assertion? When would we want to set
|
||||
// the value of a block-level expression if it wasn't CurrentStmt?
|
||||
isBlkExpr = cfg.isBlkExpr(Ex);
|
||||
|
||||
if (!isBlkExpr)
|
||||
return St;
|
||||
}
|
||||
|
||||
return BindExpr(St, Ex, V, isBlkExpr, Invalidate);
|
||||
}
|
||||
|
||||
SVal ArrayToPointer(Loc Array) {
|
||||
return StoreMgr->ArrayToPointer(Array);
|
||||
}
|
||||
|
||||
// Methods that manipulate the GDM.
|
||||
const GRState* addGDM(const GRState* St, void* Key, void* Data);
|
||||
|
||||
// Methods that query or create regions.
|
||||
bool hasStackStorage(const MemRegion* R) {
|
||||
return getRegionManager().hasStackStorage(R);
|
||||
}
|
||||
|
||||
// Methods that query & manipulate the Store.
|
||||
|
||||
void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
|
||||
StoreMgr->iterBindings(state->getStore(), F);
|
||||
}
|
||||
|
||||
|
||||
SVal GetSVal(const GRState* state, Loc LV, QualType T = QualType()) {
|
||||
return StoreMgr->Retrieve(state, LV, T);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* state, const MemRegion* R) {
|
||||
return StoreMgr->Retrieve(state, loc::MemRegionVal(R));
|
||||
}
|
||||
|
||||
SVal GetSValAsScalarOrLoc(const GRState* state, const MemRegion *R) {
|
||||
// We only want to do fetches from regions that we can actually bind
|
||||
// values. For example, SymbolicRegions of type 'id<...>' cannot
|
||||
// have direct bindings (but their can be bindings on their subregions).
|
||||
if (!R->isBoundable(getContext()))
|
||||
return UnknownVal();
|
||||
|
||||
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
|
||||
QualType T = TR->getValueType(getContext());
|
||||
if (Loc::IsLocType(T) || T->isIntegerType())
|
||||
return GetSVal(state, R);
|
||||
}
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
const GRState* BindLoc(const GRState* St, Loc LV, SVal V) {
|
||||
return StoreMgr->Bind(St, LV, V);
|
||||
}
|
||||
|
||||
void Unbind(GRState& St, Loc LV) {
|
||||
St.St = StoreMgr->Remove(St.St, LV);
|
||||
}
|
||||
|
||||
const GRState* Unbind(const GRState* St, Loc LV);
|
||||
|
||||
const GRState* getPersistentState(GRState& Impl);
|
||||
|
||||
// MakeStateWithStore - get a persistent state with the new store.
|
||||
const GRState* MakeStateWithStore(const GRState* St, Store store);
|
||||
|
||||
bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V);
|
||||
bool isEqual(const GRState* state, Expr* Ex, uint64_t);
|
||||
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Generic Data Map methods.
|
||||
//==---------------------------------------------------------------------==//
|
||||
//
|
||||
// GRStateManager and GRState support a "generic data map" that allows
|
||||
// different clients of GRState objects to embed arbitrary data within a
|
||||
// GRState object. The generic data map is essentially an immutable map
|
||||
// from a "tag" (that acts as the "key" for a client) and opaque values.
|
||||
// Tags/keys and values are simply void* values. The typical way that clients
|
||||
// generate unique tags are by taking the address of a static variable.
|
||||
// Clients are responsible for ensuring that data values referred to by a
|
||||
// the data pointer are immutable (and thus are essentially purely functional
|
||||
// data).
|
||||
//
|
||||
// The templated methods below use the GRStateTrait<T> class
|
||||
// to resolve keys into the GDM and to return data values to clients.
|
||||
//
|
||||
|
||||
// Trait based GDM dispatch.
|
||||
template <typename T>
|
||||
const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) {
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(D));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const GRState* set(const GRState* st,
|
||||
typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type V,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const GRState* add(const GRState* st,
|
||||
typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const GRState* remove(const GRState* st,
|
||||
typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
|
||||
}
|
||||
|
||||
|
||||
void* FindGDMContext(void* index,
|
||||
void* (*CreateContext)(llvm::BumpPtrAllocator&),
|
||||
void (*DeleteContext)(void*));
|
||||
|
||||
template <typename T>
|
||||
typename GRStateTrait<T>::context_type get_context() {
|
||||
void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::CreateContext,
|
||||
GRStateTrait<T>::DeleteContext);
|
||||
|
||||
return GRStateTrait<T>::MakeContext(p);
|
||||
}
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Constraints on values.
|
||||
//==---------------------------------------------------------------------==//
|
||||
//
|
||||
// Each GRState records constraints on symbolic values. These constraints
|
||||
// are managed using the ConstraintManager associated with a GRStateManager.
|
||||
// As constraints gradually accrue on symbolic values, added constraints
|
||||
// may conflict and indicate that a state is infeasible (as no real values
|
||||
// could satisfy all the constraints). This is the principal mechanism
|
||||
// for modeling path-sensitivity in GRExprEngine/GRState.
|
||||
//
|
||||
// Various "Assume" methods form the interface for adding constraints to
|
||||
// symbolic values. A call to "Assume" indicates an assumption being placed
|
||||
// on one or symbolic values. Assume methods take the following inputs:
|
||||
//
|
||||
// (1) A GRState object representing the current state.
|
||||
//
|
||||
// (2) The assumed constraint (which is specific to a given "Assume" method).
|
||||
//
|
||||
// (3) A binary value "Assumption" that indicates whether the constraint is
|
||||
// assumed to be true or false.
|
||||
//
|
||||
// The output of "Assume" are two values:
|
||||
//
|
||||
// (a) "isFeasible" is set to true or false to indicate whether or not
|
||||
// the assumption is feasible.
|
||||
//
|
||||
// (b) A new GRState object with the added constraints.
|
||||
//
|
||||
// FIXME: (a) should probably disappear since it is redundant with (b).
|
||||
// (i.e., (b) could just be set to NULL).
|
||||
//
|
||||
|
||||
const GRState* Assume(const GRState* St, SVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
const GRState *state =
|
||||
ConstraintMgr->Assume(St, Cond, Assumption, isFeasible);
|
||||
assert(!isFeasible || state);
|
||||
return isFeasible ? state : NULL;
|
||||
}
|
||||
|
||||
const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound,
|
||||
bool Assumption, bool& isFeasible) {
|
||||
const GRState *state =
|
||||
ConstraintMgr->AssumeInBound(St, Idx, UpperBound, Assumption,
|
||||
isFeasible);
|
||||
assert(!isFeasible || state);
|
||||
return isFeasible ? state : NULL;
|
||||
}
|
||||
|
||||
const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) {
|
||||
return ConstraintMgr->getSymVal(St, sym);
|
||||
}
|
||||
|
||||
void EndPath(const GRState* St) {
|
||||
ConstraintMgr->EndPath(St);
|
||||
}
|
||||
|
||||
bool scanReachableSymbols(SVal val, const GRState* state,
|
||||
SymbolVisitor& visitor);
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRStateRef - A "fat" reference to GRState that also bundles GRStateManager.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class GRStateRef {
|
||||
const GRState* St;
|
||||
GRStateManager* Mgr;
|
||||
public:
|
||||
GRStateRef(const GRState* st, GRStateManager& mgr) : St(st), Mgr(&mgr) {}
|
||||
|
||||
const GRState* getState() const { return St; }
|
||||
operator const GRState*() const { return St; }
|
||||
GRStateManager& getManager() const { return *Mgr; }
|
||||
|
||||
SVal GetSVal(Expr* Ex) {
|
||||
return Mgr->GetSVal(St, Ex);
|
||||
}
|
||||
|
||||
SVal GetBlkExprSVal(Expr* Ex) {
|
||||
return Mgr->GetBlkExprSVal(St, Ex);
|
||||
}
|
||||
|
||||
SVal GetSValAsScalarOrLoc(const Expr *Ex) {
|
||||
return Mgr->GetSValAsScalarOrLoc(St, Ex);
|
||||
}
|
||||
|
||||
SVal GetSVal(Loc LV, QualType T = QualType()) {
|
||||
return Mgr->GetSVal(St, LV, T);
|
||||
}
|
||||
|
||||
SVal GetSVal(const MemRegion* R) {
|
||||
return Mgr->GetSVal(St, R);
|
||||
}
|
||||
|
||||
SVal GetSValAsScalarOrLoc(const MemRegion *R) {
|
||||
return Mgr->GetSValAsScalarOrLoc(St, R);
|
||||
}
|
||||
|
||||
GRStateRef BindExpr(Stmt* Ex, SVal V, bool isBlkExpr, bool Invalidate) {
|
||||
return GRStateRef(Mgr->BindExpr(St, Ex, V, isBlkExpr, Invalidate), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef BindExpr(Stmt* Ex, SVal V, bool Invalidate = true) {
|
||||
return GRStateRef(Mgr->BindExpr(St, Ex, V, Invalidate), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef BindDecl(const VarDecl* VD, SVal InitVal) {
|
||||
return GRStateRef(Mgr->BindDecl(St, VD, InitVal), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef BindLoc(Loc LV, SVal V) {
|
||||
return GRStateRef(Mgr->BindLoc(St, LV, V), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef BindLoc(SVal LV, SVal V) {
|
||||
if (!isa<Loc>(LV)) return *this;
|
||||
return BindLoc(cast<Loc>(LV), V);
|
||||
}
|
||||
|
||||
GRStateRef Unbind(Loc LV) {
|
||||
return GRStateRef(Mgr->Unbind(St, LV), *Mgr);
|
||||
}
|
||||
|
||||
// Trait based GDM dispatch.
|
||||
template<typename T>
|
||||
typename GRStateTrait<T>::data_type get() const {
|
||||
return St->get<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename GRStateTrait<T>::lookup_type
|
||||
get(typename GRStateTrait<T>::key_type key) const {
|
||||
return St->get<T>(key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef set(typename GRStateTrait<T>::data_type D) {
|
||||
return GRStateRef(Mgr->set<T>(St, D), *Mgr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename GRStateTrait<T>::context_type get_context() {
|
||||
return Mgr->get_context<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef set(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type E,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
return GRStateRef(Mgr->set<T>(St, K, E, C), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef set(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type E) {
|
||||
return GRStateRef(Mgr->set<T>(St, K, E, get_context<T>()), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef add(typename GRStateTrait<T>::key_type K) {
|
||||
return GRStateRef(Mgr->add<T>(St, K, get_context<T>()), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef remove(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
return GRStateRef(Mgr->remove<T>(St, K, C), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef remove(typename GRStateTrait<T>::key_type K) {
|
||||
return GRStateRef(Mgr->remove<T>(St, K, get_context<T>()), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool contains(typename GRStateTrait<T>::key_type key) const {
|
||||
return St->contains<T>(key);
|
||||
}
|
||||
|
||||
// Lvalue methods.
|
||||
SVal GetLValue(const VarDecl* VD) {
|
||||
return Mgr->GetLValue(St, VD);
|
||||
}
|
||||
|
||||
GRStateRef Assume(SVal Cond, bool Assumption, bool& isFeasible) {
|
||||
return GRStateRef(Mgr->Assume(St, Cond, Assumption, isFeasible), *Mgr);
|
||||
}
|
||||
|
||||
template <typename CB>
|
||||
CB scanReachableSymbols(SVal val) {
|
||||
CB cb(*this);
|
||||
Mgr->scanReachableSymbols(val, St, cb);
|
||||
return cb;
|
||||
}
|
||||
|
||||
SymbolManager& getSymbolManager() { return Mgr->getSymbolManager(); }
|
||||
BasicValueFactory& getBasicVals() { return Mgr->getBasicVals(); }
|
||||
|
||||
// Pretty-printing.
|
||||
void print(std::ostream& Out, const char* nl = "\n",
|
||||
const char *sep = "") const;
|
||||
|
||||
void printStdErr() const;
|
||||
|
||||
void printDOT(std::ostream& Out) const;
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
148
include/clang/Analysis/PathSensitive/GRStateTrait.h
Normal file
148
include/clang/Analysis/PathSensitive/GRStateTrait.h
Normal file
@ -0,0 +1,148 @@
|
||||
//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- 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 partial implementations of template specializations of
|
||||
// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement
|
||||
// set/get methods for mapulating a GRState's generic data map.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H
|
||||
#define LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H
|
||||
|
||||
namespace llvm {
|
||||
class BumpPtrAllocator;
|
||||
template <typename K, typename D, typename I> class ImmutableMap;
|
||||
template <typename K, typename I> class ImmutableSet;
|
||||
template <typename T> class ImmutableList;
|
||||
template <typename T> class ImmutableListImpl;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
template <typename T> struct GRStatePartialTrait;
|
||||
|
||||
// Partial-specialization for ImmutableMap.
|
||||
|
||||
template <typename Key, typename Data, typename Info>
|
||||
struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
|
||||
typedef llvm::ImmutableMap<Key,Data,Info> data_type;
|
||||
typedef typename data_type::Factory& context_type;
|
||||
typedef Key key_type;
|
||||
typedef Data value_type;
|
||||
typedef const value_type* lookup_type;
|
||||
|
||||
static inline data_type MakeData(void* const* p) {
|
||||
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
|
||||
}
|
||||
static inline void* MakeVoidPtr(data_type B) {
|
||||
return B.getRoot();
|
||||
}
|
||||
static lookup_type Lookup(data_type B, key_type K) {
|
||||
return B.lookup(K);
|
||||
}
|
||||
static data_type Set(data_type B, key_type K, value_type E,context_type F){
|
||||
return F.Add(B, K, E);
|
||||
}
|
||||
|
||||
static data_type Remove(data_type B, key_type K, context_type F) {
|
||||
return F.Remove(B, K);
|
||||
}
|
||||
|
||||
static inline context_type MakeContext(void* p) {
|
||||
return *((typename data_type::Factory*) p);
|
||||
}
|
||||
|
||||
static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
|
||||
return new typename data_type::Factory(Alloc);
|
||||
}
|
||||
|
||||
static void DeleteContext(void* Ctx) {
|
||||
delete (typename data_type::Factory*) Ctx;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Partial-specialization for ImmutableSet.
|
||||
|
||||
template <typename Key, typename Info>
|
||||
struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
|
||||
typedef llvm::ImmutableSet<Key,Info> data_type;
|
||||
typedef typename data_type::Factory& context_type;
|
||||
typedef Key key_type;
|
||||
|
||||
static inline data_type MakeData(void* const* p) {
|
||||
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
|
||||
}
|
||||
|
||||
static inline void* MakeVoidPtr(data_type B) {
|
||||
return B.getRoot();
|
||||
}
|
||||
|
||||
static data_type Add(data_type B, key_type K, context_type F) {
|
||||
return F.Add(B, K);
|
||||
}
|
||||
|
||||
static data_type Remove(data_type B, key_type K, context_type F) {
|
||||
return F.Remove(B, K);
|
||||
}
|
||||
|
||||
static bool Contains(data_type B, key_type K) {
|
||||
return B.contains(K);
|
||||
}
|
||||
|
||||
static inline context_type MakeContext(void* p) {
|
||||
return *((typename data_type::Factory*) p);
|
||||
}
|
||||
|
||||
static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
|
||||
return new typename data_type::Factory(Alloc);
|
||||
}
|
||||
|
||||
static void DeleteContext(void* Ctx) {
|
||||
delete (typename data_type::Factory*) Ctx;
|
||||
}
|
||||
};
|
||||
|
||||
// Partial-specialization for ImmutableList.
|
||||
|
||||
template <typename T>
|
||||
struct GRStatePartialTrait< llvm::ImmutableList<T> > {
|
||||
typedef llvm::ImmutableList<T> data_type;
|
||||
typedef T key_type;
|
||||
typedef typename data_type::Factory& context_type;
|
||||
|
||||
static data_type Add(data_type L, key_type K, context_type F) {
|
||||
return F.Add(K, L);
|
||||
}
|
||||
|
||||
static inline data_type MakeData(void* const* p) {
|
||||
return p ? data_type((const llvm::ImmutableListImpl<T>*) *p)
|
||||
: data_type(0);
|
||||
}
|
||||
|
||||
static inline void* MakeVoidPtr(data_type D) {
|
||||
return (void*) D.getInternalPointer();
|
||||
}
|
||||
|
||||
static inline context_type MakeContext(void* p) {
|
||||
return *((typename data_type::Factory*) p);
|
||||
}
|
||||
|
||||
static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
|
||||
return new typename data_type::Factory(Alloc);
|
||||
}
|
||||
|
||||
static void DeleteContext(void* Ctx) {
|
||||
delete (typename data_type::Factory*) Ctx;
|
||||
}
|
||||
};
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
123
include/clang/Analysis/PathSensitive/GRTransferFuncs.h
Normal file
123
include/clang/Analysis/PathSensitive/GRTransferFuncs.h
Normal file
@ -0,0 +1,123 @@
|
||||
//== GRTransferFuncs.h - Path-Sens. Transfer Functions 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 GRTransferFuncs, which provides a base-class that
|
||||
// defines an interface for transfer functions used by GRExprEngine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRTF
|
||||
#define LLVM_CLANG_ANALYSIS_GRTF
|
||||
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRExprEngine;
|
||||
class BugReporter;
|
||||
class ObjCMessageExpr;
|
||||
class GRStmtNodeBuilderRef;
|
||||
|
||||
class GRTransferFuncs {
|
||||
friend class GRExprEngine;
|
||||
protected:
|
||||
virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLoc L, NonLoc R, QualType T) {
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
public:
|
||||
GRTransferFuncs() {}
|
||||
virtual ~GRTransferFuncs() {}
|
||||
|
||||
virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
|
||||
virtual void RegisterChecks(BugReporter& BR) {}
|
||||
|
||||
// Casts.
|
||||
|
||||
virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT) =0;
|
||||
virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT) = 0;
|
||||
|
||||
// Unary Operators.
|
||||
|
||||
virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X) = 0;
|
||||
|
||||
virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X) = 0;
|
||||
|
||||
// Binary Operators.
|
||||
// FIXME: We're moving back towards using GREXprEngine directly. No need
|
||||
// for OStates
|
||||
virtual void EvalBinOpNN(GRStateSet& OStates, GRExprEngine& Eng,
|
||||
const GRState* St, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLoc L, NonLoc R,
|
||||
QualType T);
|
||||
|
||||
virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
Loc L, Loc R) = 0;
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state,
|
||||
BinaryOperator::Opcode Op, Loc L, NonLoc R) = 0;
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
CallExpr* CE, SVal L,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ObjCMessageExpr* ME,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
// Stores.
|
||||
|
||||
virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {}
|
||||
|
||||
// End-of-path and dead symbol notification.
|
||||
|
||||
virtual void EvalEndPath(GRExprEngine& Engine,
|
||||
GREndPathNodeBuilder<GRState>& Builder) {}
|
||||
|
||||
|
||||
virtual void EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ExplodedNode<GRState>* Pred,
|
||||
Stmt* S, const GRState* state,
|
||||
SymbolReaper& SymReaper) {}
|
||||
|
||||
// Return statements.
|
||||
virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ReturnStmt* S,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
// Assumptions.
|
||||
|
||||
virtual const GRState* EvalAssume(GRStateManager& VMgr,
|
||||
const GRState* St,
|
||||
SVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return St;
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#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