Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):

http://llvm.org/svn/llvm-project/cfe/branches/release_32@168974
This commit is contained in:
Dimitry Andric 2012-12-02 13:20:44 +00:00
parent 657bc3d984
commit 13cc256e40
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=243791
svn path=/vendor/clang/clang-release_32-r168974/; revision=243792; tag=vendor/clang/clang-release_32-r168974
2195 changed files with 118295 additions and 46362 deletions

1
.gitignore vendored
View File

@ -17,6 +17,7 @@
*.pyc
# vim swap files
.*.swp
.sw?
#==============================================================================#
# Explicit files to ignore (only matches one).

View File

@ -181,16 +181,26 @@ endfunction(clang_tablegen)
macro(add_clang_library name)
llvm_process_sources(srcs ${ARGN})
if(MSVC_IDE OR XCODE)
string( REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
list( GET split_path -1 dir)
file( GLOB_RECURSE headers
../../../include/clang/StaticAnalyzer${dir}/*.h
../../../include/clang/StaticAnalyzer${dir}/*.td
../../../include/clang/StaticAnalyzer${dir}/*.def
../../include/clang${dir}/*.h
../../include/clang${dir}/*.td
../../include/clang${dir}/*.def)
set(srcs ${srcs} ${headers})
# Add public headers
file(RELATIVE_PATH lib_path
${CLANG_SOURCE_DIR}/lib/
${CMAKE_CURRENT_SOURCE_DIR}
)
if(NOT lib_path MATCHES "^[.][.]")
file( GLOB_RECURSE headers
${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.h
${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.def
)
set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
file( GLOB_RECURSE tds
${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.td
)
source_group("TableGen descriptions" FILES ${tds})
set_source_files_properties(${tds}} PROPERTIES HEADER_FILE_ONLY ON)
set(srcs ${srcs} ${headers} ${tds})
endif()
endif(MSVC_IDE OR XCODE)
if (MODULE)
set(libkind MODULE)

View File

@ -27,6 +27,10 @@ ifeq ($(MAKECMDGOALS),libs-only)
DIRS := $(filter-out tools docs, $(DIRS))
OPTIONAL_DIRS :=
endif
ifeq ($(BUILD_CLANG_ONLY),YES)
DIRS := $(filter-out docs unittests, $(DIRS))
OPTIONAL_DIRS :=
endif
###
# Common Makefile code, shared by all Clang Makefiles.

View File

@ -44,7 +44,7 @@ TODO: File Manager Speedup:
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
3. Reading the dir uses the getdirentries syscall, creating a FileEntry
for all files found.
//===---------------------------------------------------------------------===//

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
from clang.cindex import TranslationUnit
def check_completion_results(cr, expected):
assert cr is not None
assert len(cr.diagnostics) == 0
completions = [str(c) for c in cr.results]
for c in expected:
assert c in completions
def test_code_complete():
files = [('fake.c', """
/// Aaa.
int test1;
/// Bbb.
void test2(void);
void f() {
}
""")]
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True)
expected = [
"{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
"{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
"{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
]
check_completion_results(cr, expected)
def test_code_complete_availability():
files = [('fake.cpp', """
class P {
protected:
int member;
};
class Q : public P {
public:
using P::member;
};
void f(P x, Q y) {
x.; // member is inaccessible
y.; // member is accessible
}
""")]
tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files)
cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
expected = [
"{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'volatile', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
"{'Q', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None"
]
check_completion_results(cr, expected)
cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files)
expected = [
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
"{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None",
"{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None",
"{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None"
]
check_completion_results(cr, expected)

View File

@ -241,3 +241,12 @@ def test_get_tokens():
assert len(tokens) == 7
assert tokens[0].spelling == 'int'
assert tokens[1].spelling == 'foo'
def test_get_arguments():
tu = get_tu('void foo(int i, int j);')
foo = get_cursor(tu, 'foo')
arguments = list(foo.get_arguments())
assert len(arguments) == 2
assert arguments[0].spelling == "i"
assert arguments[1].spelling == "j"

View File

@ -24,6 +24,9 @@
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
@ -70,6 +73,9 @@
<ref name="USR" />
</optional>
<!-- TODO: Add exception specification. -->
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
@ -79,6 +85,15 @@
<optional>
<ref name="Parameters" />
</optional>
<zeroOrMore>
<ref name="Availability" />
</zeroOrMore>
<zeroOrMore>
<ref name="Deprecated" />
</zeroOrMore>
<zeroOrMore>
<ref name="Unavailable" />
</zeroOrMore>
<optional>
<ref name="ResultDiscussion" />
</optional>
@ -105,6 +120,9 @@
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
@ -134,6 +152,9 @@
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
@ -164,6 +185,9 @@
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
@ -194,6 +218,9 @@
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
@ -224,6 +251,9 @@
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
@ -292,11 +322,18 @@
</element>
</define>
<define name="Declaration">
<element name="Declaration">
<!-- Non-empty text content. -->
<data type="string"/>
</element>
</define>
<define name="Discussion">
<element name="Discussion">
<oneOrMore>
<zeroOrMore>
<ref name="TextBlockContent" />
</oneOrMore>
</zeroOrMore>
</element>
</define>
@ -369,6 +406,59 @@
</element>
</define>
<define name="Availability">
<element name="Availability">
<attribute name="distribution">
<data type="string" />
</attribute>
<optional>
<element name="IntroducedInVersion">
<data type="string">
<param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
</data>
</element>
</optional>
<optional>
<element name="DeprecatedInVersion">
<data type="string">
<param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
</data>
</element>
</optional>
<optional>
<element name="RemovedAfterVersion">
<data type="string">
<param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
</data>
</element>
</optional>
<optional>
<element name="DeprecationSummary">
<data type="string" />
</element>
</optional>
<optional>
<ref name="Unavailable" />
</optional>
</element>
</define>
<define name="Deprecated">
<element name="Deprecated">
<optional>
<data type="string" />
</optional>
</element>
</define>
<define name="Unavailable">
<element name="Unavailable">
<optional>
<data type="string" />
</optional>
</element>
</define>
<define name="ResultDiscussion">
<element name="ResultDiscussion">
<zeroOrMore>

View File

@ -45,17 +45,21 @@ The tool can detect the following types of bugs:
Typical slowdown introduced by AddressSanitizer is <b>2x</b>.
<h2 id="howtobuild">How to build</h2>
Follow the <a href="../get_started.html">clang build instructions</a>. <BR>
Note: CMake build does not work yet.
See <a href="http://llvm.org/bugs/show_bug.cgi?id=12272">bug 12272</a>.
Follow the <a href="../get_started.html">clang build instructions</a>.
CMake build is supported.<BR>
<h2 id="usage">Usage</h2>
Simply compile and link your program with <tt>-faddress-sanitizer</tt> flag. <BR>
Simply compile and link your program with <tt>-fsanitize=address</tt> flag. <BR>
The AddressSanitizer run-time library should be linked to the final executable,
so make sure to use <tt>clang</tt> (not <tt>ld</tt>) for the final link step.<BR>
When linking shared libraries, the AddressSanitizer run-time is not linked,
so <tt>-Wl,-z,defs</tt> may cause link errors (don't use it with AddressSanitizer). <BR>
To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
To get nicer stack traces in error messages add
<tt>-fno-omit-frame-pointer</tt>. <BR>
To get perfect stack traces you may need to disable inlining (just use <tt>-O1</tt>) and tail call
elimination (</tt>-fno-optimize-sibling-calls</tt>).
elimination (<tt>-fno-optimize-sibling-calls</tt>).
<pre>
% cat example_UseAfterFree.cc
@ -67,7 +71,15 @@ int main(int argc, char **argv) {
</pre>
<pre>
% clang -O1 -g -faddress-sanitizer -fno-omit-frame-pointer example_UseAfterFree.cc
# Compile and link
% clang -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc
</pre>
OR
<pre>
# Compile
% clang -O1 -g -fsanitize=address -fno-omit-frame-pointer -c example_UseAfterFree.cc
# Link
% clang -g -fsanitize=address example_UseAfterFree.o
</pre>
If a bug is detected, the program will print an error message to stderr and exit with a
@ -93,6 +105,13 @@ previously allocated by thread T0 here:
==9442== ABORTING
</pre>
AddressSanitizer exits on the first detected error. This is by design.
One reason: it makes the generated code smaller and faster (both by ~5%).
Another reason: this makes fixing bugs unavoidable. With Valgrind, it is often
the case that users treat Valgrind warnings as false positives
(which they are not) and don't fix them.
<h3 id="has_feature">__has_feature(address_sanitizer)</h3>
In some cases one may need to execute different code depending on whether
AddressSanitizer is enabled.
@ -107,8 +126,8 @@ can be used for this purpose.
</pre>
<h3 id="no_address_safety_analysis">__attribute__((no_address_safety_analysis))</h3>
Some code should not be instrumentated by AddressSanitizer.
One may use the function attribute
Some code should not be instrumented by AddressSanitizer.
One may use the function attribute
<a href="LanguageExtensions.html#address_sanitizer">
<tt>no_address_safety_analysis</tt></a>
to disable instrumentation of a particular function.
@ -118,18 +137,18 @@ Note: currently, this attribute will be lost if the function is inlined.
<h2 id="platforms">Supported Platforms</h2>
AddressSanitizer is supported on
<ul><li>Linux x86_64 (tested on Ubuntu 10.04).
<li>MacOS 10.6 and 10.7 (i386/x86_64).
<ul><li>Linux i386/x86_64 (tested on Ubuntu 10.04 and 12.04).
<li>MacOS 10.6, 10.7 and 10.8 (i386/x86_64).
</ul>
Support for Linux i386/ARM is in progress
Support for Linux ARM (and Android ARM) is in progress
(it may work, but is not guaranteed too).
<h2 id="limitations">Limitations</h2>
<ul>
<li> AddressSanitizer uses more real memory than a native run.
How much -- depends on the allocations sizes. The smaller the
allocations you make the bigger the overhead.
Exact overhead depends on the allocations sizes. The smaller the
allocations you make the bigger the overhead is.
<li> AddressSanitizer uses more stack memory. We have seen up to 3x increase.
<li> On 64-bit platforms AddressSanitizer maps (but not reserves)
16+ Terabytes of virtual address space.
@ -140,8 +159,8 @@ This means that tools like <tt>ulimit</tt> may not work as usually expected.
<h2 id="status">Current Status</h2>
AddressSanitizer is fully functional on supported platforms starting from LLVM 3.1.
However, the test suite is not fully integrated yet and we lack the testing
process (buildbots).
The test suite is integrated into CMake build and can be run with
<tt>make check-asan</tt> command.
<h2 id="moreinfo">More Information</h2>
<a href="http://code.google.com/p/address-sanitizer/">http://code.google.com/p/address-sanitizer</a>.

View File

@ -888,6 +888,15 @@ from non-ARC practice was acceptable because we had conservatively
banned the synthesis in order to give ourselves exactly this
leeway.</p></div>
<p>Applying <tt>__attribute__((NSObject))</tt> to a property not of
retainable object pointer type has the same behavior it does outside
of ARC: it requires the property type to be some sort of pointer and
permits the use of modifiers other than <tt>assign</tt>. These
modifiers only affect the synthesized getter and setter; direct
accesses to the ivar (even if synthesized) still have primitive
semantics, and the value in the ivar will not be automatically
released during deallocation.</p>
</div> <!-- ownership.spelling.property -->
</div> <!-- ownership.spelling -->
@ -1602,6 +1611,36 @@ implementation must be very careful to do all the other work
that <tt>NSObject</tt>'s <tt>dealloc</tt> would, which is outside the
scope of this document to describe.</p></div>
<p>The instance variables for an ARC-compiled class will be destroyed
at some point after control enters the <tt>dealloc</tt> method for the
root class of the class. The ordering of the destruction of instance
variables is unspecified, both within a single class and between
subclasses and superclasses.</p>
<div class="rationale"><p>Rationale: the traditional, non-ARC pattern
for destroying instance variables is to destroy them immediately
before calling <tt>[super&nbsp;dealloc]</tt>. Unfortunately, message
sends from the superclass are quite capable of reaching methods in the
subclass, and those methods may well read or write to those instance
variables. Making such message sends from dealloc is generally
discouraged, since the subclass may well rely on other invariants that
were broken during <tt>dealloc</tt>, but it's not so inescapably
dangerous that we felt comfortable calling it undefined behavior.
Therefore we chose to delay destroying the instance variables to a
point at which message sends are clearly disallowed: the point at
which the root class's deallocation routines take over.</p>
<p>In most code, the difference is not observable. It can, however,
be observed if an instance variable holds a strong reference to an
object whose deallocation will trigger a side-effect which must be
carefully ordered with respect to the destruction of the super class.
Such code violates the design principle that semantically important
behavior should be explicit. A simple fix is to clear the instance
variable manually during <tt>dealloc</tt>; a more holistic solution is
to move semantically important side-effects out of
<tt>dealloc</tt> and into a separate teardown phase which can rely on
working with well-formed objects.</p></div>
</div>
</div> <!-- misc.special_methods -->
@ -1865,9 +1904,9 @@ and <tt>cf_unknown_transfer</tt>.</p>
<p>A pragma is provided to facilitate the mass annotation of interfaces:</p>
<pre>#pragma arc_cf_code_audited begin
<pre>#pragma clang arc_cf_code_audited begin
...
#pragma arc_cf_code_audited end</pre>
#pragma clang arc_cf_code_audited end</pre>
<p>All C functions declared within the extent of this pragma are
treated as if annotated with the <tt>cf_audited_transfer</tt>

View File

@ -81,6 +81,10 @@ The compound statement body establishes a new lexical scope within that of its p
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 compiler is not required to capture a variable if it can prove that no references to the variable will actually be evaluated. Programmers can force a variable to be captured by referencing it in a statement at the beginning of the Block, like so:
(void) foo;
This matters when capturing the variable has side-effects, as it can in Objective-C or C++.
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.
@ -143,23 +147,25 @@ 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):
As usual, within the block, references to captured variables become const-qualified, as if they were references to members of a const object. Note that this does not change the type of a variable of reference type.
For example, given a class Foo:
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;
Foo *const block_fooPtr = fooPtr;
A Block that referenced these variables would import the variables as const variations:
const Foo block_foo = foo;
Foo &block_fooRef = fooRef;
Foo *const 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.
Captured variables are copied into the Block at the instant of evaluating the Block literal expression. They are also copied when calling Block_copy() on a Block allocated on the stack. In both cases, they are copied as if the variable were const-qualified, and it's an error if there's no such constructor.
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.
Captured variables in Blocks on the stack are destroyed when control leaves the compound statement that contains the Block literal expression. Captured variables in Blocks on the heap are destroyed when the reference count of the Block drops to zero.
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.
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, __block variables are copied using their normal qualification (i.e. without adding const). In C++11, __block variables are copied as x-values if that is possible, then as l-values if not; if both fail, it's an error. The destructor for any initial stack-based version is called at the variable's 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.
References to 'this', as well as references to non-static members of any enclosing class, are evaluated by capturing 'this' just like a normal variable of C pointer type.
Member variables that are Blocks may not be overloaded by the types of their arguments.

View File

@ -87,22 +87,14 @@ specific functionality.</p>
<h3 id="clang-check"><tt>clang-check</tt></h3>
<p>This tool combines the LibTooling framework for running a Clang tool with the
basic Clang diagnostics by syntax checking specific files in a fast, command line
interface. It can also accept flags to re-display the diagnostics in different
formats with different flags, suitable for use driving an IDE or editor.</p>
basic Clang diagnostics by syntax checking specific files in a fast, command
line interface. It can also accept flags to re-display the diagnostics in
different formats with different flags, suitable for use driving an IDE or
editor. Furthermore, it can be used in fixit-mode to directly apply fixit-hints
offered by clang.</p>
<p>FIXME: Link to user-oriented clang-check documentation.</p>
<h3 id="clang-fixit"><tt>clang-fixit</tt> (Not yet implemented!)</h3>
<p>A tool which specifically applies the Clang fix-it hint diagnostic technology
on top of a dedicated tool. It is designed to explore alternative interfaces for
applying fix-it hints, including automatic application, prompting users with
options for different fixes, etc.</p>
<p><b>NB:</b> The clang-fixit tool is planned, but not yet implemented.</p>
<p>FIXME: Link to user-oriented clang-fixit documentation.</p>
<!-- ======================================================================= -->
<h2 id="registerplugin">Extra Clang Tools</h2>
<!-- ======================================================================= -->

View File

@ -77,12 +77,38 @@ $PATH. Try to run it on any .cpp file inside the LLVM source tree:</p>
<p>If you're using vim, it's convenient to have clang-check integrated. Put this
into your .vimrc:</p>
<pre>
set makeprg=clang-check\ %
map &lt;F5&gt; :make&lt;CR&gt;&lt;CR&gt;
function! ClangCheckImpl(cmd)
if &amp;autowrite | wall | endif
echo "Running " . a:cmd . " ..."
let l:output = system(a:cmd)
cexpr l:output
cwindow
let w:quickfix_title = a:cmd
if v:shell_error != 0
cc
endif
let g:clang_check_last_cmd = a:cmd
endfunction
function! ClangCheck()
let l:filename = expand('%')
if l:filename =~ '\.\(cpp\|cxx\|cc\|c\)$'
call ClangCheckImpl("clang-check " . l:filename)
elseif exists("g:clang_check_last_cmd")
call ClangCheckImpl(g:clang_check_last_cmd)
else
echo "Can't detect file's compilation arguments and no previous clang-check invocation!"
endif
endfunction
nmap &lt;silent&gt; &lt;F5&gt; :call ClangCheck()&lt;CR&gt;&lt;CR&gt;
</pre>
<p>When editing C++ code, hit F5 to reparse the current buffer. The output will
go into the error window, which you can enable with <code>:cope</code>.</p>
<p>When editing a .cpp/.cxx/.cc/.c file, hit F5 to reparse the file. In case
the current file has a different extension (for example, .h), F5 will re-run
the last clang-check invocation made from this vim instance (if any). The
output will go into the error window, which is opened automatically when
clang-check finds errors, and can be re-opened with <code>:cope</code>.</p>
<p>Other <code>clang-check</code> options that can be useful when working with
clang AST:</p>

View File

@ -502,7 +502,9 @@ code, the source ranges, and the caret. However, this behavior isn't required.
Instead of formatting and printing out the diagnostics, this implementation just
captures and remembers the diagnostics as they fly by. Then -verify compares
the list of produced diagnostics to the list of expected ones. If they disagree,
it prints out its own output.
it prints out its own output. Full documentation for the -verify mode can be
found in the Clang API documentation for VerifyDiagnosticConsumer, <a
href="/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details">here</a>.
</p>
<p>There are many other possible implementations of this interface, and this is

View File

@ -1007,6 +1007,7 @@ struct is_convertible_to {
<li><code>__is_convertible_to</code> (Microsoft)</li>
<li><code>__is_empty</code> (GNU, Microsoft)</li>
<li><code>__is_enum</code> (GNU, Microsoft)</li>
<li><code>__is_interface_class</code> (Microsoft)</li>
<li><code>__is_pod</code> (GNU, Microsoft)</li>
<li><code>__is_polymorphic</code> (GNU, Microsoft)</li>
<li><code>__is_union</code> (GNU, Microsoft)</li>
@ -1582,7 +1583,8 @@ path between it and the next switch label.</p>
<pre>
// compile with -Wimplicit-fallthrough
switch (n) {
case 33:
case 22:
case 33: // no warning: no statements between case labels
f();
case 44: // warning: unannotated fall-through
g();
@ -1981,8 +1983,8 @@ int fcntl(int fd, int cmd, ...)
<p>Use <tt>__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx,
type_tag_idx)))</tt> on a function declaration to specify that the
function a type tag that determines the pointee type of some other pointer
argument.</p>
function accepts a type tag that determines the pointee type of some other
pointer argument.</p>
<p>For example:</p>
<blockquote>

130
docs/LibASTMatchers.html Normal file
View File

@ -0,0 +1,130 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Matching the Clang AST</title>
<link type="text/css" rel="stylesheet" href="../menu.css" />
<link type="text/css" rel="stylesheet" href="../content.css" />
</head>
<body>
<!--#include virtual="../menu.html.incl"-->
<div id="content">
<h1>Matching the Clang AST</h1>
<p>This document explains how to use Clang's LibASTMatchers to match interesting
nodes of the AST and execute code that uses the matched nodes. Combined with
<a href="LibTooling.html">LibTooling</a>, LibASTMatchers helps to write
code-to-code transformation tools or query tools.</p>
<p>We assume basic knowledge about the Clang AST. See the
<a href="IntroductionToTheClangAST.html">Introduction to the Clang AST</a> if
you want to learn more about how the AST is structured.</p>
<!-- FIXME: create tutorial and link to the tutorial -->
<!-- ======================================================================= -->
<h2 id="intro">Introduction</h2>
<!-- ======================================================================= -->
<p>LibASTMatchers provides a domain specific language to create predicates on Clang's
AST. This DSL is written in and can be used from C++, allowing users to write
a single program to both match AST nodes and access the node's C++ interface
to extract attributes, source locations, or any other information provided on
the AST level.</p>
<p>AST matchers are predicates on nodes in the AST. Matchers are created
by calling creator functions that allow building up a tree of matchers, where
inner matchers are used to make the match more specific.</p>
</p>For example, to create a matcher that matches all class or union declarations
in the AST of a translation unit, you can call
<a href="LibASTMatchersReference.html#recordDecl0Anchor">recordDecl()</a>.
To narrow the match down, for example to find all class or union declarations with the name "Foo",
insert a <a href="LibASTMatchersReference.html#hasName0Anchor">hasName</a>
matcher: the call recordDecl(hasName("Foo")) returns a matcher that matches classes
or unions that are named "Foo", in any namespace. By default, matchers that accept
multiple inner matchers use an implicit <a href="LibASTMatchersReference.html#allOf0Anchor">allOf()</a>.
This allows further narrowing down the match, for example to match all classes
that are derived from "Bar": recordDecl(hasName("Foo"), isDerivedFrom("Bar")).</p>
<!-- ======================================================================= -->
<h2 id="writing">How to create a matcher</h2>
<!-- ======================================================================= -->
<p>With more than a thousand classes in the Clang AST, one can quickly get lost
when trying to figure out how to create a matcher for a specific pattern. This
section will teach you how to use a rigorous step-by-step pattern to build the
matcher you are interested in. Note that there will always be matchers missing
for some part of the AST. See the section about <a href="#writing">how to write
your own AST matchers</a> later in this document.</p>
<p>The precondition to using the matchers is to understand how the AST
for what you want to match looks like. The <a href="IntroductionToTheClangAST.html">Introduction to the Clang AST</a>
teaches you how to dump a translation unit's AST into a human readable format.</p>
<!-- FIXME: Introduce link to ASTMatchersTutorial.html -->
<!-- FIXME: Introduce link to ASTMatchersCookbook.html -->
<p>In general, the strategy to create the right matchers is:</p>
<ol>
<li>Find the outermost class in Clang's AST you want to match.</li>
<li>Look at the <a href="LibASTMatchersReference.html">AST Matcher Reference</a> for matchers that either match the
node you're interested in or narrow down attributes on the node.</li>
<li>Create your outer match expression. Verify that it works as expected.</li>
<li>Examine the matchers for what the next inner node you want to match is.</li>
<li>Repeat until the matcher is finished.</li>
</ol>
<!-- ======================================================================= -->
<h2 id="binding">Binding nodes in match expressions</h2>
<!-- ======================================================================= -->
<p>Matcher expressions allow you to specify which parts of the AST are interesting
for a certain task. Often you will want to then do something with the nodes
that were matched, like building source code transformations.</p>
<p>To that end, matchers that match specific AST nodes (so called node matchers)
are bindable; for example, recordDecl(hasName("MyClass")).bind("id") will bind
the matched recordDecl node to the string "id", to be later retrieved in the
<a href="http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder_1_1MatchCallback.html">match callback</a>.</p>
<!-- FIXME: Introduce link to ASTMatchersTutorial.html -->
<!-- FIXME: Introduce link to ASTMatchersCookbook.html -->
<!-- ======================================================================= -->
<h2 id="writing">Writing your own matchers</h2>
<!-- ======================================================================= -->
<p>There are multiple different ways to define a matcher, depending on its
type and flexibility.</p>
<ul>
<li><b>VariadicDynCastAllOfMatcher&ltBase, Derived></b><p>Those match all nodes
of type <i>Base</i> if they can be dynamically casted to <i>Derived</i>. The
names of those matchers are nouns, which closely resemble <i>Derived</i>.
VariadicDynCastAllOfMatchers are the backbone of the matcher hierarchy. Most
often, your match expression will start with one of them, and you can
<a href="#binding">bind</a> the node they represent to ids for later processing.</p>
<p>VariadicDynCastAllOfMatchers are callable classes that model variadic
template functions in C++03. They take an aribtrary number of Matcher&lt;Derived>
and return a Matcher&lt;Base>.</p></li>
<li><b>AST_MATCHER_P(Type, Name, ParamType, Param)</b><p> Most matcher definitions
use the matcher creation macros. Those define both the matcher of type Matcher&lt;Type>
itself, and a matcher-creation function named <i>Name</i> that takes a parameter
of type <i>ParamType</i> and returns the corresponding matcher.</p>
<p>There are multiple matcher definition macros that deal with polymorphic return
values and different parameter counts. See <a href="http://clang.llvm.org/doxygen/ASTMatchersMacros_8h.html">ASTMatchersMacros.h</a>.
</p></li>
<li><b>Matcher creation functions</b><p>Matchers are generated by nesting
calls to matcher creation functions. Most of the time those functions are either
created by using VariadicDynCastAllOfMatcher or the matcher creation macros
(see below). The free-standing functions are an indication that this matcher
is just a combination of other matchers, as is for example the case with
<a href="LibASTMatchersReference.html#callee1Anchor">callee</a>.</p></li>
</ul>
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -16,24 +16,27 @@
<p>LibTooling is a library to support writing standalone tools based on
Clang. This document will provide a basic walkthrough of how to write
a tool using LibTooling.</p>
<p>For the information on how to setup Clang Tooling for LLVM see
<a href="HowToSetupToolingForLLVM.html">HowToSetupToolingForLLVM.html</a></p>
<!-- ======================================================================= -->
<h2 id="intro">Introduction</h2>
<!-- ======================================================================= -->
<p>Tools built with LibTooling, like Clang Plugins, run FrontendActions over
code. <!-- See FIXME for a tutorial on how to write FrontendActions. -->
<p>Tools built with LibTooling, like Clang Plugins, run
<code>FrontendActions</code> over code.
<!-- See FIXME for a tutorial on how to write FrontendActions. -->
In this tutorial, we'll demonstrate the different ways of running clang's
SyntaxOnlyAction, which runs a quick syntax check, over a bunch of
<code>SyntaxOnlyAction</code>, which runs a quick syntax check, over a bunch of
code.</p>
<!-- ======================================================================= -->
<h2 id="runoncode">Parsing a code snippet in memory.</h2>
<!-- ======================================================================= -->
<p>If you ever wanted to run a FrontendAction over some sample code, for example
to unit test parts of the Clang AST, runToolOnCode is what you looked for. Let
me give you an example:
<p>If you ever wanted to run a <code>FrontendAction</code> over some sample
code, for example to unit test parts of the Clang AST,
<code>runToolOnCode</code> is what you looked for. Let me give you an example:
<pre>
#include "clang/Tooling/Tooling.h"
@ -48,53 +51,44 @@ me give you an example:
<h2 id="standalonetool">Writing a standalone tool.</h2>
<!-- ======================================================================= -->
<p>Once you unit tested your FrontendAction to the point where it cannot
possibly break, it's time to create a standalone tool. For a standalone tool
to run clang, it first needs to figure out what command line arguments to use
for a specified file. To that end we create a CompilationDatabase.</p>
<p>Once you unit tested your <code>FrontendAction</code> to the point where it
cannot possibly break, it's time to create a standalone tool. For a standalone
tool to run clang, it first needs to figure out what command line arguments to
use for a specified file. To that end we create a
<code>CompilationDatabase</code>. There are different ways to create a
compilation database, and we need to support all of them depending on
command-line options. There's the <code>CommonOptionsParser</code> class
that takes the responsibility to parse command-line parameters related to
compilation databases and inputs, so that all tools share the implementation.
</p>
<h3 id="compilationdb">Creating a compilation database.</h3>
<p>CompilationDatabase provides static factory functions to help with parsing
compile commands from a build directory or the command line. The following code
allows for both explicit specification of a compile command line, as well as
retrieving the compile commands lines from a database.
<h3 id="parsingcommonoptions">Parsing common tools options.</h3>
<p><code>CompilationDatabase</code> can be read from a build directory or the
command line. Using <code>CommonOptionsParser</code> allows for explicit
specification of a compile command line, specification of build path using the
<code>-p</code> command-line option, and automatic location of the compilation
database using source files paths.
<pre>
#include "clang/Tooling/CommonOptionsParser.h"
using namespace clang::tooling;
int main(int argc, const char **argv) {
// First, try to create a fixed compile command database from the command line
// arguments.
llvm::OwningPtr&lt;CompilationDatabase> Compilations(
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
// CommonOptionsParser constructor will parse arguments and create a
// CompilationDatabase. In case of error it will terminate the program.
CommonOptionsParser OptionsParser(argc, argv);
// Next, use normal llvm command line parsing to get the tool specific
// parameters.
cl::ParseCommandLineOptions(argc, argv);
if (!Compilations) {
// In case the user did not specify the compile command line via positional
// command line arguments after "--", try to load the compile commands from
// a database in the specified build directory or auto-detect it from a
// source file.
std::string ErrorMessage;
if (!BuildPath.empty()) {
Compilations.reset(
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage));
} else {
Compilations.reset(CompilationDatabase::autoDetectFromSource(
SourcePaths[0], ErrorMessage));
}
// If there is still no valid compile command database, we don't know how
// to run the tool.
if (!Compilations)
llvm::report_fatal_error(ErrorMessage);
}
// Use OptionsParser.GetCompilations() and OptionsParser.GetSourcePathList()
// to retrieve CompilationDatabase and the list of input file paths.
}
</pre>
</p>
<h3 id="tool">Creating and running a ClangTool.</h3>
<p>Once we have a CompilationDatabase, we can create a ClangTool and run our
FrontendAction over some code. For example, to run the SyntaxOnlyAction over
the files "a.cc" and "b.cc" one would write:
<p>Once we have a <code>CompilationDatabase</code>, we can create a
<code>ClangTool</code> and run our <code>FrontendAction</code> over some code.
For example, to run the <code>SyntaxOnlyAction</code> over the files "a.cc" and
"b.cc" one would write:
<pre>
// A clang tool can run over a number of sources in the same process...
std::vector&lt;std::string> Sources;
@ -103,7 +97,7 @@ the files "a.cc" and "b.cc" one would write:
// We hand the CompilationDatabase we created and the sources to run over into
// the tool constructor.
ClangTool Tool(*Compilations, Sources);
ClangTool Tool(OptionsParser.GetCompilations(), Sources);
// The ClangTool needs a new FrontendAction for each translation unit we run
// on. Thus, it takes a FrontendActionFactory as parameter. To create a
@ -117,40 +111,29 @@ the files "a.cc" and "b.cc" one would write:
<p>Now we combine the two previous steps into our first real tool. This example
tool is also checked into the clang tree at tools/clang-check/ClangCheck.cpp.
<pre>
#include "llvm/Support/CommandLine.h"
// Declares clang::SyntaxOnlyAction.
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
// Declares llvm::cl::extrahelp.
#include "llvm/Support/CommandLine.h"
using namespace clang::tooling;
using namespace llvm;
cl::opt&lt;std::string> BuildPath(
"p",
cl::desc("&lt;build-path>"),
cl::Optional);
// CommonOptionsParser declares HelpMessage with a description of the common
// command-line options related to the compilation database and input files.
// It's nice to have this help message in all tools.
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
cl::list&lt;std::string> SourcePaths(
cl::Positional,
cl::desc("&lt;source0> [... &lt;sourceN>]"),
cl::OneOrMore);
// A help message for this specific tool can be added afterwards.
static cl::extrahelp MoreHelp("\nMore help text...");
int main(int argc, const char **argv) {
llvm::OwningPtr&lt;CompilationDatabase> Compilations(
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
cl::ParseCommandLineOptions(argc, argv);
if (!Compilations) {
std::string ErrorMessage;
Compilations.reset(
!BuildPath.empty() ?
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage) :
CompilationDatabase::autoDetectFromSource(SourcePaths[0], ErrorMessage)
);
if (!Compilations)
llvm::report_fatal_error(ErrorMessage);
}
ClangTool Tool(*Compilations, SourcePaths);
return Tool.run(newFrontendActionFactory&lt;clang::SyntaxOnlyAction>());
CommonOptionsParser OptionsParser(argc, argv);
ClangTool Tool(OptionsParser.GetCompilations(),
OptionsParser.GetSourcePathList());
return Tool.run(newFrontendActionFactory&lt;clang::SyntaxOnlyAction&gt;());
}
</pre>
</p>

View File

@ -178,7 +178,7 @@ A C string literal prefixed by the <code>'@'</code> token denotes an <code>NSStr
<pre>
// Partition command line arguments into positional and option arguments.
NSMutableArray *args = [NSMutableArray new];
NSMutableDictionary *options = [NSMutableArray new];
NSMutableDictionary *options = [NSMutableDictionary new];
while (--argc) {
const char *arg = *++argv;
if (strncmp(arg, "--", 2) == 0) {

View File

@ -2,7 +2,7 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Precompiled Headers (PCH)</title>
<title>Precompiled Header and Modules Internals</title>
<link type="text/css" rel="stylesheet" href="../menu.css">
<link type="text/css" rel="stylesheet" href="../content.css">
<style type="text/css">
@ -18,10 +18,10 @@
<div id="content">
<h1>Precompiled Headers</h1>
<h1>Precompiled Header and Modules Internals</h1>
<p>This document describes the design and implementation of Clang's
precompiled headers (PCH). If you are interested in the end-user
precompiled headers (PCH) and modules. If you are interested in the end-user
view, please see the <a
href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
@ -30,7 +30,7 @@
<li><a href="#usage">Using Precompiled Headers with
<tt>clang</tt></a></li>
<li><a href="#philosophy">Design Philosophy</a></li>
<li><a href="#contents">Precompiled Header Contents</a>
<li><a href="#contents">Serialized AST File Contents</a>
<ul>
<li><a href="#metadata">Metadata Block</a></li>
<li><a href="#sourcemgr">Source Manager Block</a></li>
@ -42,8 +42,9 @@
<li><a href="#method-pool">Method Pool Block</a></li>
</ul>
</li>
<li><a href="#tendrils">Precompiled Header Integration
Points</a></li>
<li><a href="#tendrils">AST Reader Integration Points</a></li>
<li><a href="#chained">Chained precompiled headers</a></li>
<li><a href="#modules">Modules</a></li>
</ul>
<h2 id="usage">Using Precompiled Headers with <tt>clang</tt></h2>
@ -94,30 +95,39 @@ with the <b><tt>-include-pch</tt></b> option:</p>
require the PCH file to be up-to-date.</li>
</ul>
<p>Clang's precompiled headers are designed with a compact on-disk
representation, which minimizes both PCH creation time and the time
required to initially load the PCH file. The PCH file itself contains
<p>Modules, as implemented in Clang, use the same mechanisms as
precompiled headers to save a serialized AST file (one per module) and
use those AST modules. From an implementation standpoint, modules are
a generalization of precompiled headers, lifting a number of
restrictions placed on precompiled headers. In particular, there can
only be one precompiled header and it must be included at the
beginning of the translation unit. The extensions to the AST file
format required for modules are discussed in the section on <a href="#modules">modules</a>.</p>
<p>Clang's AST files are designed with a compact on-disk
representation, which minimizes both creation time and the time
required to initially load the AST file. The AST file itself contains
a serialized representation of Clang's abstract syntax trees and
supporting data structures, stored using the same compressed bitstream
as <a href="http://llvm.org/docs/BitCodeFormat.html">LLVM's bitcode
file format</a>.</p>
<p>Clang's precompiled headers are loaded "lazily" from disk. When a
PCH file is initially loaded, Clang reads only a small amount of data
from the PCH file to establish where certain important data structures
<p>Clang's AST files are loaded "lazily" from disk. When an
AST file is initially loaded, Clang reads only a small amount of data
from the AST file to establish where certain important data structures
are stored. The amount of data read in this initial load is
independent of the size of the PCH file, such that a larger PCH file
does not lead to longer PCH load times. The actual header data in the
PCH file--macros, functions, variables, types, etc.--is loaded only
independent of the size of the AST file, such that a larger AST file
does not lead to longer AST load times. The actual header data in the
AST file--macros, functions, variables, types, etc.--is loaded only
when it is referenced from the user's code, at which point only that
entity (and those entities it depends on) are deserialized from the
PCH file. With this approach, the cost of using a precompiled header
AST file. With this approach, the cost of using an AST file
for a translation unit is proportional to the amount of code actually
used from the header, rather than being proportional to the size of
the header itself.</p>
used from the AST file, rather than being proportional to the size of
the AST file itself.</p>
<p>When given the <code>-print-stats</code> option, Clang produces
statistics describing how much of the precompiled header was actually
statistics describing how much of the AST file was actually
loaded from disk. For a simple "Hello, World!" program that includes
the Apple <code>Cocoa.h</code> header (which is built as a precompiled
header), this option illustrates how little of the actual precompiled
@ -143,7 +153,7 @@ header is required:</p>
<p>For this small program, only a tiny fraction of the source
locations, types, declarations, identifiers, and macros were actually
deserialized from the precompiled header. These statistics can be
useful to determine whether the precompiled header implementation can
useful to determine whether the AST file implementation can
be improved by making more of the implementation lazy.</p>
<p>Precompiled headers can be chained. When you create a PCH while
@ -153,13 +163,15 @@ example, you could create a PCH out of all the headers that are very
commonly used throughout your project, and then create a PCH for every
single source file in the project that includes the code that is
specific to that file, so that recompiling the file itself is very fast,
without duplicating the data from the common headers for every file.</p>
without duplicating the data from the common headers for every
file. The mechanisms behind chained precompiled headers are discussed
in a <a href="#chained">later section</a>.
<h2 id="contents">Precompiled Header Contents</h2>
<h2 id="contents">AST File Contents</h2>
<img src="PCHLayout.png" style="float:right" alt="Precompiled header layout">
<p>Clang's precompiled headers are organized into several different
<p>Clang's AST files are organized into several different
blocks, each of which contains the serialized representation of a part
of Clang's internal representation. Each of the blocks corresponds to
either a block or a record within <a
@ -167,19 +179,19 @@ either a block or a record within <a
format</a>. The contents of each of these logical blocks are described
below.</p>
<p>For a given precompiled header, the <a
<p>For a given AST file, the <a
href="http://llvm.org/cmds/llvm-bcanalyzer.html"><code>llvm-bcanalyzer</code></a>
utility can be used to examine the actual structure of the bitstream
for the precompiled header. This information can be used both to help
understand the structure of the precompiled header and to isolate
areas where precompiled headers can still be optimized, e.g., through
for the AST file. This information can be used both to help
understand the structure of the AST file and to isolate
areas where AST files can still be optimized, e.g., through
the introduction of abbreviations.</p>
<h3 id="metadata">Metadata Block</h3>
<p>The metadata block contains several records that provide
information about how the precompiled header was built. This metadata
is primarily used to validate the use of a precompiled header. For
information about how the AST file was built. This metadata
is primarily used to validate the use of an AST file. For
example, a precompiled header built for a 32-bit x86 target cannot be used
when compiling for a 64-bit x86 target. The metadata block contains
information about:</p>
@ -187,17 +199,17 @@ information about:</p>
<dl>
<dt>Language options</dt>
<dd>Describes the particular language dialect used to compile the
PCH file, including major options (e.g., Objective-C support) and more
AST file, including major options (e.g., Objective-C support) and more
minor options (e.g., support for "//" comments). The contents of this
record correspond to the <code>LangOptions</code> class.</dd>
<dt>Target architecture</dt>
<dd>The target triple that describes the architecture, platform, and
ABI for which the PCH file was generated, e.g.,
ABI for which the AST file was generated, e.g.,
<code>i386-apple-darwin9</code>.</dd>
<dt>PCH version</dt>
<dd>The major and minor version numbers of the precompiled header
<dt>AST version</dt>
<dd>The major and minor version numbers of the AST file
format. Changes in the minor version number should not affect backward
compatibility, while changes in the major version number imply that a
newer compiler cannot read an older precompiled header (and
@ -205,11 +217,11 @@ vice-versa).</dd>
<dt>Original file name</dt>
<dd>The full path of the header that was used to generate the
precompiled header.</dd>
AST file.</dd>
<dt>Predefines buffer</dt>
<dd>Although not explicitly stored as part of the metadata, the
predefines buffer is used in the validation of the precompiled header.
predefines buffer is used in the validation of the AST file.
The predefines buffer itself contains code generated by the compiler
to initialize the preprocessor state according to the current target,
platform, and command-line options. For example, the predefines buffer
@ -220,26 +232,14 @@ contents are verified along with the rest of the metadata.</dd>
</dl>
<p>A chained PCH file (that is, one that references another PCH) has
a slightly different metadata block, which contains the following
information:</p>
<p>A chained PCH file (that is, one that references another PCH) and a
module (which may import other modules) have additional metadata
containing the list of all AST files that this AST file depends
on. Each of those files will be loaded along with this AST file.</p>
<dl>
<dt>Referenced file</dt>
<dd>The name of the referenced PCH file. It is looked up like a file
specified using -include-pch.</dd>
<dt>PCH version</dt>
<dd>This is the same as in normal PCH files.</dd>
<dt>Original file name</dt>
<dd>The full path of the header that was used to generate this
precompiled header.</dd>
</dl>
<p>The language options, target architecture and predefines buffer data
is taken from the end of the chain, since they have to match anyway.</p>
<p>For chained precompiled headers, the language options, target
architecture and predefines buffer data is taken from the end of the
chain, since they have to match anyway.</p>
<h3 id="sourcemgr">Source Manager Block</h3>
@ -248,10 +248,10 @@ Clang's <a
href="InternalsManual.html#SourceLocation">SourceManager</a> class,
which handles the mapping from source locations (as represented in
Clang's abstract syntax tree) into actual column/line positions within
a source file or macro instantiation. The precompiled header's
a source file or macro instantiation. The AST file's
representation of the source manager also includes information about
all of the headers that were (transitively) included when building the
precompiled header.</p>
AST file.</p>
<p>The bulk of the source manager block is dedicated to information
about the various files, buffers, and macro instantiations into which
@ -259,18 +259,18 @@ a source location can refer. Each of these is referenced by a numeric
"file ID", which is a unique number (allocated starting at 1) stored
in the source location. Clang serializes the information for each kind
of file ID, along with an index that maps file IDs to the position
within the PCH file where the information about that file ID is
within the AST file where the information about that file ID is
stored. The data associated with a file ID is loaded only when
required by the front end, e.g., to emit a diagnostic that includes a
macro instantiation history inside the header itself.</p>
<p>The source manager block also contains information about all of the
headers that were included when building the precompiled header. This
headers that were included when building the AST file. This
includes information about the controlling macro for the header (e.g.,
when the preprocessor identified that the contents of the header
dependent on a macro like <code>LLVM_CLANG_SOURCEMANAGER_H</code>)
along with a cached version of the results of the <code>stat()</code>
system calls performed when building the precompiled header. The
system calls performed when building the AST file. The
latter is particularly useful in reducing system time when searching
for include files.</p>
@ -279,8 +279,8 @@ for include files.</p>
<p>The preprocessor block contains the serialized representation of
the preprocessor. Specifically, it contains all of the macros that
have been defined by the end of the header used to build the
precompiled header, along with the token sequences that comprise each
macro. The macro definitions are only read from the PCH file when the
AST file, along with the token sequences that comprise each
macro. The macro definitions are only read from the AST file when the
name of the macro first occurs in the program. This lazy loading of
macro definitions is triggered by lookups into the <a
href="#idtable">identifier table</a>.</p>
@ -290,8 +290,8 @@ macro definitions is triggered by lookups into the <a
<p>The types block contains the serialized representation of all of
the types referenced in the translation unit. Each Clang type node
(<code>PointerType</code>, <code>FunctionProtoType</code>, etc.) has a
corresponding record type in the PCH file. When types are deserialized
from the precompiled header, the data within the record is used to
corresponding record type in the AST file. When types are deserialized
from the AST file, the data within the record is used to
reconstruct the appropriate type node using the AST context.</p>
<p>Each type has a unique type ID, which is an integer that uniquely
@ -300,10 +300,10 @@ less than <code>NUM_PREDEF_TYPE_IDS</code> represent predefined types
(<code>void</code>, <code>float</code>, etc.), while other
"user-defined" type IDs are assigned consecutively from
<code>NUM_PREDEF_TYPE_IDS</code> upward as the types are encountered.
The PCH file has an associated mapping from the user-defined types
The AST file has an associated mapping from the user-defined types
block to the location within the types block where the serialized
representation of that type resides, enabling lazy deserialization of
types. When a type is referenced from within the PCH file, that
types. When a type is referenced from within the AST file, that
reference is encoded using the type ID shifted left by 3 bits. The
lower three bits are used to represent the <code>const</code>,
<code>volatile</code>, and <code>restrict</code> qualifiers, as in
@ -316,19 +316,20 @@ class.</p>
<p>The declarations block contains the serialized representation of
all of the declarations referenced in the translation unit. Each Clang
declaration node (<code>VarDecl</code>, <code>FunctionDecl</code>,
etc.) has a corresponding record type in the PCH file. When
declarations are deserialized from the precompiled header, the data
etc.) has a corresponding record type in the AST file. When
declarations are deserialized from the AST file, the data
within the record is used to build and populate a new instance of the
corresponding <code>Decl</code> node. As with types, each declaration
node has a numeric ID that is used to refer to that declaration within
the PCH file. In addition, a lookup table provides a mapping from that
the AST file. In addition, a lookup table provides a mapping from that
numeric ID to the offset within the precompiled header where that
declaration is described.</p>
<p>Declarations in Clang's abstract syntax trees are stored
hierarchically. At the top of the hierarchy is the translation unit
(<code>TranslationUnitDecl</code>), which contains all of the
declarations in the translation unit. These declarations (such as
declarations in the translation unit but is not actually written as a
specific declaration node. Its child declarations (such as
functions or struct types) may also contain other declarations inside
them, and so on. Within Clang, each declaration is stored within a <a
href="http://clang.llvm.org/docs/InternalsManual.html#DeclContext">declaration
@ -339,7 +340,7 @@ in a structure) and iterate over the declarations stored within a
context (e.g., iterate over all of the fields of a structure for
structure layout).</p>
<p>In Clang's precompiled header format, deserializing a declaration
<p>In Clang's AST file format, deserializing a declaration
that is a <code>DeclContext</code> is a separate operation from
deserializing all of the declarations stored within that declaration
context. Therefore, Clang will deserialize the translation unit
@ -354,14 +355,11 @@ the name-lookup and iteration behavior described above:</p>
<code>x</code> within a given declaration context (for example,
during semantic analysis of the expression <code>p-&gt;x</code>,
where <code>p</code>'s type is defined in the precompiled header),
Clang deserializes a hash table mapping from the names within that
declaration context to the declaration IDs that represent each
visible declaration with that name. The entire hash table is
deserialized at this point (into the <code>llvm::DenseMap</code>
stored within each <code>DeclContext</code> object), but the actual
declarations are not yet deserialized. In a second step, those
declarations with the name <code>x</code> will be deserialized and
will be used as the result of name lookup.</li>
Clang refers to an on-disk hash table that maps from the names
within that declaration context to the declaration IDs that
represent each visible declaration with that name. The actual
declarations will then be deserialized to provide the results of
name lookup.</li>
<li>When the front end performs iteration over all of the
declarations within a declaration context, all of those declarations
@ -376,7 +374,7 @@ the name-lookup and iteration behavior described above:</p>
<h3 id="stmt">Statements and Expressions</h3>
<p>Statements and expressions are stored in the precompiled header in
<p>Statements and expressions are stored in the AST file in
both the <a href="#types">types</a> and the <a
href="#decls">declarations</a> blocks, because every statement or
expression will be associated with either a type or declaration. The
@ -389,10 +387,10 @@ function.</p>
<p>As with types and declarations, each statement and expression kind
in Clang's abstract syntax tree (<code>ForStmt</code>,
<code>CallExpr</code>, etc.) has a corresponding record type in the
precompiled header, which contains the serialized representation of
AST file, which contains the serialized representation of
that statement or expression. Each substatement or subexpression
within an expression is stored as a separate record (which keeps most
records to a fixed size). Within the precompiled header, the
records to a fixed size). Within the AST file, the
subexpressions of an expression are stored, in reverse order, prior to the expression
that owns those expression, using a form of <a
href="http://en.wikipedia.org/wiki/Reverse_Polish_notation">Reverse
@ -420,7 +418,7 @@ they are part of a different expression.</p>
<h3 id="idtable">Identifier Table Block</h3>
<p>The identifier table block contains an on-disk hash table that maps
each identifier mentioned within the precompiled header to the
each identifier mentioned within the AST file to the
serialized representation of the identifier's information (e.g, the
<code>IdentifierInfo</code> structure). The serialized representation
contains:</p>
@ -438,17 +436,20 @@ contains:</p>
declarations.</li>
</ul>
<p>When a precompiled header is loaded, the precompiled header
<p>When an AST file is loaded, the AST file reader
mechanism introduces itself into the identifier table as an external
lookup source. Thus, when the user program refers to an identifier
that has not yet been seen, Clang will perform a lookup into the
identifier table. If an identifier is found, its contents (macro
definitions, flags, top-level declarations, etc.) will be deserialized, at which point the corresponding <code>IdentifierInfo</code> structure will have the same contents it would have after parsing the headers in the precompiled header.</p>
definitions, flags, top-level declarations, etc.) will be
deserialized, at which point the corresponding
<code>IdentifierInfo</code> structure will have the same contents it
would have after parsing the headers in the AST file.</p>
<p>Within the PCH file, the identifiers used to name declarations are represented with an integral value. A separate table provides a mapping from this integral value (the identifier ID) to the location within the on-disk
<p>Within the AST file, the identifiers used to name declarations are represented with an integral value. A separate table provides a mapping from this integral value (the identifier ID) to the location within the on-disk
hash table where that identifier is stored. This mapping is used when
deserializing the name of a declaration, the identifier of a token, or
any other construct in the PCH file that refers to a name.</p>
any other construct in the AST file that refers to a name.</p>
<h3 id="method-pool">Method Pool Block</h3>
@ -457,7 +458,7 @@ serves two purposes: it provides a mapping from the names of
Objective-C selectors to the set of Objective-C instance and class
methods that have that particular selector (which is required for
semantic analysis in Objective-C) and also stores all of the selectors
used by entities within the precompiled header. The design of the
used by entities within the AST file. The design of the
method pool is similar to that of the <a href="#idtable">identifier
table</a>: the first time a particular selector is formed during the
compilation of the program, Clang will search in the on-disk hash
@ -468,25 +469,25 @@ structure (<code>Sema::InstanceMethodPool</code> and
respectively).</p>
<p>As with identifiers, selectors are represented by numeric values
within the PCH file. A separate index maps these numeric selector
within the AST file. A separate index maps these numeric selector
values to the offset of the selector within the on-disk hash table,
and will be used when de-serializing an Objective-C method declaration
(or other Objective-C construct) that refers to the selector.</p>
<h2 id="tendrils">Precompiled Header Integration Points</h2>
<h2 id="tendrils">AST Reader Integration Points</h2>
<p>The "lazy" deserialization behavior of precompiled headers requires
<p>The "lazy" deserialization behavior of AST files requires
their integration into several completely different submodules of
Clang. For example, lazily deserializing the declarations during name
lookup requires that the name-lookup routines be able to query the
precompiled header to find entities within the PCH file.</p>
AST file to find entities stored there.</p>
<p>For each Clang data structure that requires direct interaction with
the precompiled header logic, there is an abstract class that provides
the interface between the two modules. The <code>PCHReader</code>
class, which handles the loading of a precompiled header, inherits
the AST reader logic, there is an abstract class that provides
the interface between the two modules. The <code>ASTReader</code>
class, which handles the loading of an AST file, inherits
from all of these abstract classes to provide lazy deserialization of
Clang's data structures. <code>PCHReader</code> implements the
Clang's data structures. <code>ASTReader</code> implements the
following abstract classes:</p>
<dl>
@ -505,7 +506,7 @@ following abstract classes:</p>
<dd>This abstract interface is associated with the
<code>IdentifierTable</code> class, and is used whenever the
program source refers to an identifier that has not yet been seen.
In this case, the precompiled header implementation searches for
In this case, the AST reader searches for
this identifier within its <a href="#idtable">identifier table</a>
to load any top-level declarations or macros associated with that
identifier.</dd>
@ -513,7 +514,7 @@ following abstract classes:</p>
<dt><code>ExternalASTSource</code></dt>
<dd>This abstract interface is associated with the
<code>ASTContext</code> class, and is used whenever the abstract
syntax tree nodes need to loaded from the precompiled header. It
syntax tree nodes need to loaded from the AST file. It
provides the ability to de-serialize declarations and types
identified by their numeric values, read the bodies of functions
when required, and read the declarations stored within a
@ -526,6 +527,131 @@ following abstract classes:</p>
pool</a>.</dd>
</dl>
<h2 id="chained">Chained precompiled headers</h2>
<p>Chained precompiled headers were initially intended to improve the
performance of IDE-centric operations such as syntax highlighting and
code completion while a particular source file is being edited by the
user. To minimize the amount of reparsing required after a change to
the file, a form of precompiled header--called a precompiled
<i>preamble</i>--is automatically generated by parsing all of the
headers in the source file, up to and including the last
#include. When only the source file changes (and none of the headers
it depends on), reparsing of that source file can use the precompiled
preamble and start parsing after the #includes, so parsing time is
proportional to the size of the source file (rather than all of its
includes). However, the compilation of that translation unit
may already use a precompiled header: in this case, Clang will create
the precompiled preamble as a chained precompiled header that refers
to the original precompiled header. This drastically reduces the time
needed to serialize the precompiled preamble for use in reparsing.</p>
<p>Chained precompiled headers get their name because each precompiled header
can depend on one other precompiled header, forming a chain of
dependencies. A translation unit will then include the precompiled
header that starts the chain (i.e., nothing depends on it). This
linearity of dependencies is important for the semantic model of
chained precompiled headers, because the most-recent precompiled
header can provide information that overrides the information provided
by the precompiled headers it depends on, just like a header file
<code>B.h</code> that includes another header <code>A.h</code> can
modify the state produced by parsing <code>A.h</code>, e.g., by
<code>#undef</code>'ing a macro defined in <code>A.h</code>.</p>
<p>There are several ways in which chained precompiled headers
generalize the AST file model:</p>
<dl>
<dt>Numbering of IDs</dt>
<dd>Many different kinds of entities--identifiers, declarations,
types, etc.---have ID numbers that start at 1 or some other
predefined constant and grow upward. Each precompiled header records
the maximum ID number it has assigned in each category. Then, when a
new precompiled header is generated that depends on (chains to)
another precompiled header, it will start counting at the next
available ID number. This way, one can determine, given an ID
number, which AST file actually contains the entity.</dd>
<dt>Name lookup</dt>
<dd>When writing a chained precompiled header, Clang attempts to
write only information that has changed from the precompiled header
on which it is based. This changes the lookup algorithm for the
various tables, such as the <a href="#idtable">identifier table</a>:
the search starts at the most-recent precompiled header. If no entry
is found, lookup then proceeds to the identifier table in the
precompiled header it depends on, and so one. Once a lookup
succeeds, that result is considered definitive, overriding any
results from earlier precompiled headers.</dd>
<dt>Update records</dt>
<dd>There are various ways in which a later precompiled header can
modify the entities described in an earlier precompiled header. For
example, later precompiled headers can add entries into the various
name-lookup tables for the translation unit or namespaces, or add
new categories to an Objective-C class. Each of these updates is
captured in an "update record" that is stored in the chained
precompiled header file and will be loaded along with the original
entity.</dd>
</dl>
<h2 id="modules">Modules</h2>
<p>Modules generalize the chained precompiled header model yet
further, from a linear chain of precompiled headers to an arbitrary
directed acyclic graph (DAG) of AST files. All of the same techniques
used to make chained precompiled headers work---ID number, name
lookup, update records---are shared with modules. However, the DAG
nature of modules introduce a number of additional complications to
the model:
<dl>
<dt>Numbering of IDs</dt>
<dd>The simple, linear numbering scheme used in chained precompiled
headers falls apart with the module DAG, because different modules
may end up with different numbering schemes for entities they
imported from common shared modules. To account for this, each
module file provides information about which modules it depends on
and which ID numbers it assigned to the entities in those modules,
as well as which ID numbers it took for its own new entities. The
AST reader then maps these "local" ID numbers into a "global" ID
number space for the current translation unit, providing a 1-1
mapping between entities (in whatever AST file they inhabit) and
global ID numbers. If that translation unit is then serialized into
an AST file, this mapping will be stored for use when the AST file
is imported.</dd>
<dt>Declaration merging</dt>
<dd>It is possible for a given entity (from the language's
perspective) to be declared multiple times in different places. For
example, two different headers can have the declaration of
<tt>printf</tt> or could forward-declare <tt>struct stat</tt>. If
each of those headers is included in a module, and some third party
imports both of those modules, there is a potentially serious
problem: name lookup for <tt>printf</tt> or <tt>struct stat</tt> will
find both declarations, but the AST nodes are unrelated. This would
result in a compilation error, due to an ambiguity in name
lookup. Therefore, the AST reader performs declaration merging
according to the appropriate language semantics, ensuring that the
two disjoint declarations are merged into a single redeclaration
chain (with a common canonical declaration), so that it is as if one
of the headers had been included before the other.</dd>
<dt>Name Visibility</dt>
<dd>Modules allow certain names that occur during module creation to
be "hidden", so that they are not part of the public interface of
the module and are not visible to its clients. The AST reader
maintains a "visible" bit on various AST nodes (declarations, macros,
etc.) to indicate whether that particular AST node is currently
visible; the various name lookup mechanisms in Clang inspect the
visible bit to determine whether that entity, which is still in the
AST (because other, visible AST nodes may depend on it), can
actually be found by name lookup. When a new (sub)module is
imported, it may make existing, non-visible, already-deserialized
AST nodes visible; it is the responsibility of the AST reader to
find and update these AST nodes when it is notified of the import.</dd>
</dl>
</div>
</body>

View File

@ -170,6 +170,16 @@ int f(vector&lt;map&lt;int, double&gt;&gt;);
</li>
<li>Clang's <tt>-fcatch-undefined-behavior</tt> option has been renamed to
<tt>-fsanitize=undefined</tt> and has grown the ability to check for several
new types of undefined behavior. See the Users Manual for more information.
<!-- Flesh this out prior to release. -->
<!-- Document renaming of -faddress-sanitizer and -fthread-sanitizer. -->
</li>
</ul>
<h4 id="tlsmodel">Support for <code>tls_model</code> attribute</h4>

View File

@ -37,9 +37,8 @@ Typical slowdown introduced by ThreadSanitizer is <b>5x-15x</b> (TODO: these num
approximate so far).
<h2 id="howtobuild">How to build</h2>
Follow the <a href="../get_started.html">clang build instructions</a>. <BR>
Note: CMake build does not work yet.
See <a href="http://llvm.org/bugs/show_bug.cgi?id=12272">bug 12272</a>.
Follow the <a href="../get_started.html">clang build instructions</a>.
CMake build is supported.<BR>
<h2 id="platforms">Supported Platforms</h2>
ThreadSanitizer is supported on Linux x86_64 (tested on Ubuntu 10.04). <BR>
@ -49,8 +48,8 @@ Support for 32-bit platforms is problematic and not yet planned.
<h2 id="usage">Usage</h2>
Simply compile your program with <tt>-fthread-sanitizer -fPIE</tt> and link it
with <tt>-fthread-sanitizer -pie</tt>.<BR>
Simply compile your program with <tt>-fsanitize=thread -fPIE</tt> and link it
with <tt>-fsanitize=thread -pie</tt>.<BR>
To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
Use <tt>-g</tt> to get file names and line numbers in the warning messages. <BR>
@ -73,7 +72,7 @@ int main() {
</pre>
<pre>
% clang -fthread-sanitizer -g -O1 tiny_race.c -fPIE -pie
% clang -fsanitize=thread -g -O1 tiny_race.c -fPIE -pie
</pre>
If a bug is detected, the program will print an error message to stderr.
@ -111,7 +110,9 @@ This means that tools like <tt>ulimit</tt> may not work as usually expected.
ThreadSanitizer is in alpha stage.
It is known to work on large C++ programs using pthreads, but we do not promise
anything (yet). <BR>
C++11 threading is not yet supported.
C++11 threading is not yet supported. <BR>
The test suite is integrated into CMake build and can be run with
<tt>make check-tsan</tt> command. <BR>
We are actively working on enhancing the tool -- stay tuned.
Any help, especially in the form of minimized standalone tests is more than welcome.

View File

@ -874,33 +874,77 @@ likely to affect PCH files that reference a large number of headers.</p>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<dl>
<dt id="opt_fcatch-undefined-behavior"><b>-fcatch-undefined-behavior</b>: Turn
on runtime code generation to check for undefined behavior.</dt>
<dt id="opt_fsanitize"><b>-fsanitize=check1,check2</b>: Turn on runtime checks
for various forms of undefined behavior.</dt>
<dd>This option controls whether Clang adds runtime checks for various forms of
undefined behavior, and is disabled by default. If a check fails, a diagnostic
message is produced at runtime explaining the problem. The main checks are:
<dd>This option, which defaults to off, controls whether or not Clang
adds runtime checks for undefined runtime behavior. If a check fails,
<tt>__builtin_trap()</tt> is used to indicate failure.
The checks are:
<ul>
<li>Subscripting where the static type of one operand is a variable
which is decayed from an array type and the other operand is
greater than the size of the array or less than zero.</li>
<li>Shift operators where the amount shifted is greater or equal to the
promoted bit-width of the left-hand-side or less than zero.</li>
<li>If control flow reaches __builtin_unreachable.
<li>When llvm implements more __builtin_object_size support, reads and
writes for objects that __builtin_object_size indicates we aren't
accessing valid memory. Bit-fields and vectors are not yet checked.
<li id="opt_fsanitize_address"><tt>-fsanitize=address</tt>:
<a href="AddressSanitizer.html">AddressSanitizer</a>, a memory error
detector.</li>
<li id="opt_fsanitize_thread"><tt>-fsanitize=thread</tt>:
<a href="ThreadSanitizer.html">ThreadSanitizer</a>, an <em>experimental</em>
data race detector. Not ready for widespread use.</li>
<li id="opt_fsanitize_undefined"><tt>-fsanitize=undefined</tt>:
Enables all the checks listed below.</li>
</ul>
The following more fine-grained checks are also available:
<ul>
<li id="opt_fsanitize_alignment"><tt>-fsanitize=alignment</tt>:
Use of a misaligned pointer or creation of a misaligned reference.</li>
<li id="opt_fsanitize_divide-by-zero"><tt>-fsanitize=divide-by-zero</tt>:
Division by zero.</li>
<li id="opt_fsanitize_float-cast-overflow"><tt>-fsanitize=float-cast-overflow</tt>:
Conversion to, from, or between floating-point types which would overflow
the destination.</li>
<li id="opt_fsanitize_null"><tt>-fsanitize=null</tt>:
Use of a null pointer or creation of a null reference.</li>
<li id="opt_fsanitize_object-size"><tt>-fsanitize=object-size</tt>:
An attempt to use bytes which the optimizer can determine are not part of
the object being accessed.
The sizes of objects are determined using <tt>__builtin_object_size</tt>, and
consequently may be able to detect more problems at higher optimization
levels.</li>
<li id="opt_fsanitize_return"><tt>-fsanitize=return</tt>:
In C++, reaching the end of a value-returning function without returning a
value.</li>
<li id="opt_fsanitize_shift"><tt>-fsanitize=shift</tt>:
Shift operators where the amount shifted is greater or equal to the
promoted bit-width of the left hand side or less than zero, or where
the left hand side is negative. For a signed left shift, also checks
for signed overflow in C, and for unsigned overflow in C++.</li>
<li id="opt_fsanitize_signed-integer-overflow"><tt>-fsanitize=signed-integer-overflow</tt>:
Signed integer overflow, including all the checks added by <tt>-ftrapv</tt>,
and checking for overflow in signed division (<tt>INT_MIN / -1</tt>).</li>
<li id="opt_fsanitize_unreachable"><tt>-fsanitize=unreachable</tt>:
If control flow reaches __builtin_unreachable.</li>
<li id="opt_fsanitize_vla-bound"><tt>-fsanitize=vla-bound</tt>:
A variable-length array whose bound does not evaluate to a positive value.</li>
<li id="opt_fsanitize_vptr"><tt>-fsanitize=vptr</tt>:
Use of an object whose vptr indicates that it is of the wrong dynamic type,
or that its lifetime has not begun or has ended. Incompatible with
<tt>-fno-rtti</tt>.</li>
</ul>
The <tt>-fsanitize=</tt> argument must also be provided when linking, in order
to link to the appropriate runtime library. It is not possible to combine the
<tt>-fsanitize=address</tt> and <tt>-fsanitize=thread</tt> checkers in the same
program.
</dd>
<dt id="opt_faddress-sanitizer"><b>-f[no-]address-sanitizer</b>:
Turn on <a href="AddressSanitizer.html">AddressSanitizer</a>,
a memory error detector.
Deprecated synonym for <a href="#opt_fsanitize_address"><tt>-f[no-]sanitize=address</tt></a>.
<dt id="opt_fthread-sanitizer"><b>-f[no-]thread-sanitizer</b>:
Turn on ThreadSanitizer, an <em>experimental</em> data race detector.
Not ready for widespread use.
Deprecated synonym for <a href="#opt_fsanitize_address"><tt>-f[no-]sanitize=thread</tt></a>.
<dt id="opt_fcatch-undefined-behavior"><b>-fcatch-undefined-behavior</b>:
Deprecated synonym for <a href="#opt_fsanitize_undefined"><tt>-fsanitize=undefined</tt></a>.
<dt id="opt_fno-assume-sane-operator-new"><b>-fno-assume-sane-operator-new</b>:
Don't assume that the C++'s new operator is sane.</dt>

View File

@ -1,96 +1,355 @@
Inlining
========
Inlining Modes
-----------------------
-analyzer-ipa=none - All inlining is disabled.
-analyzer-ipa=inlining - Turns on inlining when we can confidently find the function/method body corresponding to the call. (C functions, static functions, devirtualized C++ methods, ObjC class methods, ObjC instance methods when we are confident about the dynamic type of the instance).
-analyzer-ipa=dynamic - Inline instance methods for which the type is determined at runtime and we are not 100% sure that our type info is correct. For virtual calls, inline the most plausible definition.
-analyzer-ipa=dynamic-bifurcate - Same as -analyzer-ipa=dynamic, but the path is split. We inline on one branch and do not inline on the other. This mode does not drop the coverage in cases when the parent class has code that is only exercised when some of its methods are overriden.
There are several options that control which calls the analyzer will consider for
inlining. The major one is -analyzer-ipa:
-analyzer-ipa=none - All inlining is disabled. This is the only mode available
in LLVM 3.1 and earlier and in Xcode 4.3 and earlier.
-analyzer-ipa=basic-inlining - Turns on inlining for C functions, C++ static
member functions, and blocks -- essentially, the calls that behave like
simple C function calls. This is essentially the mode used in Xcode 4.4.
-analyzer-ipa=inlining - Turns on inlining when we can confidently find the
function/method body corresponding to the call. (C functions, static
functions, devirtualized C++ methods, Objective-C class methods, Objective-C
instance methods when ExprEngine is confident about the dynamic type of the
instance).
-analyzer-ipa=dynamic - Inline instance methods for which the type is
determined at runtime and we are not 100% sure that our type info is
correct. For virtual calls, inline the most plausible definition.
-analyzer-ipa=dynamic-bifurcate - Same as -analyzer-ipa=dynamic, but the path
is split. We inline on one branch and do not inline on the other. This mode
does not drop the coverage in cases when the parent class has code that is
only exercised when some of its methods are overridden.
Currently, -analyzer-ipa=dynamic-bifurcate is the default mode.
While -analyzer-ipa determines in general how aggressively the analyzer will try to
inline functions, several additional options control which types of functions can
inlined, in an all-or-nothing way. These options use the analyzer's configuration
table, so they are all specified as follows:
-analyzer-config OPTION=VALUE
### c++-inlining ###
This option controls which C++ member functions may be inlined.
-analyzer-config c++-inlining=[none | methods | constructors | destructors]
Each of these modes implies that all the previous member function kinds will be
inlined as well; it doesn't make sense to inline destructors without inlining
constructors, for example.
The default c++-inlining mode is 'methods', meaning only regular member
functions and overloaded operators will be inlined. Note that no C++ member
functions will be inlined under -analyzer-ipa=none or
-analyzer-ipa=basic-inlining.
### c++-template-inlining ###
This option controls whether C++ templated functions may be inlined.
-analyzer-config c++-template-inlining=[true | false]
Currently, template functions are considered for inlining by default.
The motivation behind this option is that very generic code can be a source
of false positives, either by considering paths that the caller considers
impossible (by some unstated precondition), or by inlining some but not all
of a deep implementation of a function.
### c++-stdlib-inlining ###
This option controls whether functions from the C++ standard library, including
methods of the container classes in the Standard Template Library, should be
considered for inlining.
-analyzer-config c++-template-inlining=[true | false]
Currently, C++ standard library functions are NOT considered for inlining by default.
The standard library functions and the STL in particular are used ubiquitously
enough that our tolerance for false positives is even lower here. A false
positive due to poor modeling of the STL leads to a poor user experience, since
most users would not be comfortable adding assertions to system headers in order
to silence analyzer warnings.
Currently, -analyzer-ipa=inlining is the default mode.
Basics of Implementation
-----------------------
The low-level mechanism of inlining a function is handled in ExprEngine::inlineCall and ExprEngine::processCallExit. If the conditions are right for inlining, a CallEnter node is created and added to the analysis work list. The CallEnter node marks the change to a new LocationContext representing the called function, and its state includes the contents of the new stack frame. When the CallEnter node is actually processed, its single successor will be a edge to the first CFG block in the function.
The low-level mechanism of inlining a function is handled in
ExprEngine::inlineCall and ExprEngine::processCallExit.
Exiting an inlined function is a bit more work, fortunately broken up into reasonable steps:
1. The CoreEngine realizes we're at the end of an inlined call and generates a CallExitBegin node.
2. ExprEngine takes over (in processCallExit) and finds the return value of the function, if it has one. This is bound to the expression that triggered the call. (In the case of calls without origin expressions, such as destructors, this step is skipped.)
3. Dead symbols and bindings are cleaned out from the state, including any local bindings.
4. A CallExitEnd node is generated, which marks the transition back to the caller's LocationContext.
5. Custom post-call checks are processed and the final nodes are pushed back onto the work list, so that evaluation of the caller can continue.
If the conditions are right for inlining, a CallEnter node is created and added
to the analysis work list. The CallEnter node marks the change to a new
LocationContext representing the called function, and its state includes the
contents of the new stack frame. When the CallEnter node is actually processed,
its single successor will be a edge to the first CFG block in the function.
Exiting an inlined function is a bit more work, fortunately broken up into
reasonable steps:
1. The CoreEngine realizes we're at the end of an inlined call and generates a
CallExitBegin node.
2. ExprEngine takes over (in processCallExit) and finds the return value of the
function, if it has one. This is bound to the expression that triggered the
call. (In the case of calls without origin expressions, such as destructors,
this step is skipped.)
3. Dead symbols and bindings are cleaned out from the state, including any local
bindings.
4. A CallExitEnd node is generated, which marks the transition back to the
caller's LocationContext.
5. Custom post-call checks are processed and the final nodes are pushed back
onto the work list, so that evaluation of the caller can continue.
Retry Without Inlining
----------------------
In some cases, we would like to retry analysis without inlining a particular
call.
Currently, we use this technique to recover coverage in case we stop
analyzing a path due to exceeding the maximum block count inside an inlined
function.
When this situation is detected, we walk up the path to find the first node
before inlining was started and enqueue it on the WorkList with a special
ReplayWithoutInlining bit added to it (ExprEngine::replayWithoutInlining). The
path is then re-analyzed from that point without inlining that particular call.
Deciding When to Inline
-----------------------
In some cases, we would like to retry analyzes without inlining the particular call. Currently, we use this technique to recover the coverage in case we stop analyzing a path due to exceeding the maximum block count inside an inlined function. When this situation is detected, we walk up the path to find the first node before inlining was started and enqueue it on the WorkList with a special ReplayWithoutInlining bit added to it (ExprEngine::replayWithoutInlining).
In general, the analyzer attempts to inline as much as possible, since it
provides a better summary of what actually happens in the program. There are
some cases, however, where the analyzer chooses not to inline:
Deciding when to inline
-----------------------
In general, we try to inline as much as possible, since it provides a better summary of what actually happens in the program. However, there are some cases where we choose not to inline:
- if there is no definition available (of course)
- if we can't create a CFG or compute variable liveness for the function
- if we reach a cutoff of maximum stack depth (to avoid infinite recursion)
- if the function is variadic
- in C++, we don't inline constructors unless we know the destructor will be inlined as well
- in C++, we don't inline allocators (custom operator new implementations), since we don't properly handle deallocators (at the time of this writing)
- "Dynamic" calls are handled specially; see below.
- Engine:FunctionSummaries map stores additional information about declarations, some of which is collected at runtime based on previous analyzes of the function. We do not inline functions which were not profitable to inline in a different context (for example, if the maximum block count was exceeded, see Retry Without Inlining).
- If there is no definition available for the called function or method. In
this case, there is no opportunity to inline.
- If the CFG cannot be constructed for a called function, or the liveness
cannot be computed. These are prerequisites for analyzing a function body,
with or without inlining.
- If the LocationContext chain for a given ExplodedNode reaches a maximum cutoff
depth. This prevents unbounded analysis due to infinite recursion, but also
serves as a useful cutoff for performance reasons.
- If the function is variadic. This is not a hard limitation, but an engineering
limitation.
Tracked by: <rdar://problem/12147064> Support inlining of variadic functions
- In C++, constructors are not inlined unless the destructor call will be
processed by the ExprEngine. Thus, if the CFG was built without nodes for
implicit destructors, or if the destructors for the given object are not
represented in the CFG, the constructor will not be inlined. (As an exception,
constructors for objects with trivial constructors can still be inlined.)
See "C++ Caveats" below.
- In C++, ExprEngine does not inline custom implementations of operator 'new'
or operator 'delete', nor does it inline the constructors and destructors
associated with these. See "C++ Caveats" below.
- Calls resulting in "dynamic dispatch" are specially handled. See more below.
- The FunctionSummaries map stores additional information about declarations,
some of which is collected at runtime based on previous analyses.
We do not inline functions which were not profitable to inline in a different
context (for example, if the maximum block count was exceeded; see
"Retry Without Inlining").
Dynamic calls and devirtualization
Dynamic Calls and Devirtualization
----------------------------------
"Dynamic" calls are those that are resolved at runtime, such as C++ virtual method calls and Objective-C message sends. Due to the path-sensitive nature of the analyzer, we may be able to figure out the dynamic type of the object whose method is being called and thus "devirtualize" the call, i.e. find the actual method that will be called at runtime. (Obviously this is not always possible.) This is handled by CallEvent's getRuntimeDefinition method.
Type information is tracked as DynamicTypeInfo, stored within the program state. If no DynamicTypeInfo has been explicitly set for a region, it will be inferred from the region's type or associated symbol. Information from symbolic regions is weaker than from true typed regions; a C++ object declared "A obj" is known to have the class 'A', but a reference "A &ref" may dynamically be a subclass of 'A'. The DynamicTypePropagation checker gathers and propagates the type information.
"Dynamic" calls are those that are resolved at runtime, such as C++ virtual
method calls and Objective-C message sends. Due to the path-sensitive nature of
the analysis, the analyzer may be able to reason about the dynamic type of the
object whose method is being called and thus "devirtualize" the call.
(Warning: not all of the existing analyzer code has been retrofitted to use DynamicTypeInfo, nor is it universally appropriate. In particular, DynamicTypeInfo always applies to a region with all casts stripped off, but sometimes the information provided by casts can be useful.)
This path-sensitive devirtualization occurs when the analyzer can determine what
method would actually be called at runtime. This is possible when the type
information is constrained enough for a simulated C++/Objective-C object that
the analyzer can make such a decision.
When asked to provide a definition, the CallEvents for dynamic calls will use the type info in their state to provide the best definition of the method to be called. In some cases this devirtualization can be perfect or near-perfect, and we can inline the definition as usual. In others we can make a guess, but report that our guess may not be the method actually called at runtime.
== DynamicTypeInfo ==
The -analyzer-ipa option has four different modes: none, inlining, dynamic, and dynamic-bifurcate. Under -analyzer-ipa=dynamic, all dynamic calls are inlined, whether we are certain or not that this will actually be the definition used at runtime. Under -analyzer-ipa=inlining, only "near-perfect" devirtualized calls are inlined*, and other dynamic calls are evaluated conservatively (as if no definition were available).
As the analyzer analyzes a path, it may accrue information to refine the
knowledge about the type of an object. This can then be used to make better
decisions about the target method of a call.
* Currently, no Objective-C messages are not inlined under -analyzer-ipa=inlining, even if we are reasonably confident of the type of the receiver. We plan to enable this once we have tested our heuristics more thoroughly.
Such type information is tracked as DynamicTypeInfo. This is path-sensitive
data that is stored in ProgramState, which defines a mapping from MemRegions to
an (optional) DynamicTypeInfo.
The last option, -analyzer-ipa=dynamic-bifurcate, behaves similarly to "dynamic", but performs a conservative invalidation in the general virtual case in /addition/ to inlining. The details of this are discussed below.
If no DynamicTypeInfo has been explicitly set for a MemRegion, it will be lazily
inferred from the region's type or associated symbol. Information from symbolic
regions is weaker than from true typed regions.
EXAMPLE: A C++ object declared "A obj" is known to have the class 'A', but a
reference "A &ref" may dynamically be a subclass of 'A'.
The DynamicTypePropagation checker gathers and propagates DynamicTypeInfo,
updating it as information is observed along a path that can refine that type
information for a region.
WARNING: Not all of the existing analyzer code has been retrofitted to use
DynamicTypeInfo, nor is it universally appropriate. In particular,
DynamicTypeInfo always applies to a region with all casts stripped
off, but sometimes the information provided by casts can be useful.
== RuntimeDefinition ==
The basis of devirtualization is CallEvent's getRuntimeDefinition() method,
which returns a RuntimeDefinition object. When asked to provide a definition,
the CallEvents for dynamic calls will use the DynamicTypeInfo in their
ProgramState to attempt to devirtualize the call. In the case of no dynamic
dispatch, or perfectly constrained devirtualization, the resulting
RuntimeDefinition contains a Decl corresponding to the definition of the called
function, and RuntimeDefinition::mayHaveOtherDefinitions will return FALSE.
In the case of dynamic dispatch where our information is not perfect, CallEvent
can make a guess, but RuntimeDefinition::mayHaveOtherDefinitions will return
TRUE. The RuntimeDefinition object will then also include a MemRegion
corresponding to the object being called (i.e., the "receiver" in Objective-C
parlance), which ExprEngine uses to decide whether or not the call should be
inlined.
== Inlining Dynamic Calls ==
The -analyzer-ipa option has five different modes: none, basic-inlining,
inlining, dynamic, and dynamic-bifurcate. Under -analyzer-ipa=dynamic, all
dynamic calls are inlined, whether we are certain or not that this will actually
be the definition used at runtime. Under -analyzer-ipa=inlining, only
"near-perfect" devirtualized calls are inlined*, and other dynamic calls are
evaluated conservatively (as if no definition were available).
* Currently, no Objective-C messages are not inlined under
-analyzer-ipa=inlining, even if we are reasonably confident of the type of the
receiver. We plan to enable this once we have tested our heuristics more
thoroughly.
The last option, -analyzer-ipa=dynamic-bifurcate, behaves similarly to
"dynamic", but performs a conservative invalidation in the general virtual case
in *addition* to inlining. The details of this are discussed below.
As stated above, -analyzer-ipa=basic-inlining does not inline any C++ member
functions or Objective-C method calls, even if they are non-virtual or can be
safely devirtualized.
Bifurcation
-----------
ExprEngine::BifurcateCall implements the -analyzer-ipa=dynamic-bifurcate mode. When a call is made on a region with dynamic type information, we bifurcate the path and add the region's processing mode to the GDM. Currently, there are 2 modes: DynamicDispatchModeInlined and DynamicDispatchModeConservative. Going forward, we consult the state of the region to make decisions on whether the calls should be inlined or not, which ensures that we have at most one split per region. The modes model the cases when the dynamic type information is perfectly correct and when the info is not correct (i.e. where the region is a subclass of the type we store in DynamicTypeInfo).
Bifurcation mode allows for increased coverage in cases where the parent method contains code which is only executed when the class is subclassed. The disadvantages of this mode are a (considerable?) performance hit and the possibility of false positives on the path where the conservative mode is used.
ExprEngine::BifurcateCall implements the -analyzer-ipa=dynamic-bifurcate
mode.
When a call is made on an object with imprecise dynamic type information
(RuntimeDefinition::mayHaveOtherDefinitions() evaluates to TRUE), ExprEngine
bifurcates the path and marks the object's region (retrieved from the
RuntimeDefinition object) with a path-sensitive "mode" in the ProgramState.
Currently, there are 2 modes:
DynamicDispatchModeInlined - Models the case where the dynamic type information
of the receiver (MemoryRegion) is assumed to be perfectly constrained so
that a given definition of a method is expected to be the code actually
called. When this mode is set, ExprEngine uses the Decl from
RuntimeDefinition to inline any dynamically dispatched call sent to this
receiver because the function definition is considered to be fully resolved.
DynamicDispatchModeConservative - Models the case where the dynamic type
information is assumed to be incorrect, for example, implies that the method
definition is overriden in a subclass. In such cases, ExprEngine does not
inline the methods sent to the receiver (MemoryRegion), even if a candidate
definition is available. This mode is conservative about simulating the
effects of a call.
Going forward along the symbolic execution path, ExprEngine consults the mode
of the receiver's MemRegion to make decisions on whether the calls should be
inlined or not, which ensures that there is at most one split per region.
At a high level, "bifurcation mode" allows for increased semantic coverage in
cases where the parent method contains code which is only executed when the
class is subclassed. The disadvantages of this mode are a (considerable?)
performance hit and the possibility of false positives on the path where the
conservative mode is used.
Objective-C Message Heuristics
------------------------------
We rely on a set of heuristics to partition the set of ObjC method calls into ones that require bifurcation and ones that do not (can or cannot be a subclass). Below are the cases when we consider that the dynamic type of the object is precise (cannot be a subclass):
- If the object was created with +alloc or +new and initialized with an -init method.
- If the calls are property accesses using dot syntax. This is based on the assumption that children rarely override properties, or do so in an essentially compatible way.
- If the class interface is declared inside the main source file. In this case it is unlikely that it will be subclassed.
- If the method is not declared outside of main source file, either by the receiver's class or by any superclasses.
ExprEngine relies on a set of heuristics to partition the set of Objective-C
method calls into those that require bifurcation and those that do not. Below
are the cases when the DynamicTypeInfo of the object is considered precise
(cannot be a subclass):
C++ Inlining Caveats
- If the object was created with +alloc or +new and initialized with an -init
method.
- If the calls are property accesses using dot syntax. This is based on the
assumption that children rarely override properties, or do so in an
essentially compatible way.
- If the class interface is declared inside the main source file. In this case
it is unlikely that it will be subclassed.
- If the method is not declared outside of main source file, either by the
receiver's class or by any superclasses.
C++ Caveats
--------------------
C++11 [class.cdtor]p4 describes how the vtable of an object is modified as it is being constructed or destructed; that is, the type of the object depends on which base constructors have been completed. This is tracked using dynamic type info in the DynamicTypePropagation checker.
Temporaries are poorly modelled right now because we're not confident in the placement
C++11 [class.cdtor]p4 describes how the vtable of an object is modified as it is
being constructed or destructed; that is, the type of the object depends on
which base constructors have been completed. This is tracked using
DynamicTypeInfo in the DynamicTypePropagation checker.
'new' is poorly modelled due to some nasty CFG/design issues (elaborated in PR12014). 'delete' is essentially not modelled at all.
There are several limitations in the current implementation:
Arrays of objects are modeled very poorly right now. We run only the first constructor and first destructor. Because of this, we don't inline any constructors or destructors for arrays.
- Temporaries are poorly modeled right now because we're not confident in the
placement of their destructors in the CFG. We currently won't inline their
constructors unless the destructor is trivial, and don't process their
destructors at all, not even to invalidate the region.
- 'new' is poorly modeled due to some nasty CFG/design issues. This is tracked
in PR12014. 'delete' is not modeled at all.
- Arrays of objects are modeled very poorly right now. ExprEngine currently
only simulates the first constructor and first destructor. Because of this,
ExprEngine does not inline any constructors or destructors for arrays.
CallEvent
=========
A CallEvent represents a specific call to a function, method, or other body of code. It is path-sensitive, containing both the current state (ProgramStateRef) and stack space (LocationContext), and provides uniform access to the argument values and return type of a call, no matter how the call is written in the source or what sort of code body is being invoked.
A CallEvent represents a specific call to a function, method, or other body of
code. It is path-sensitive, containing both the current state (ProgramStateRef)
and stack space (LocationContext), and provides uniform access to the argument
values and return type of a call, no matter how the call is written in the
source or what sort of code body is being invoked.
(For those familiar with Cocoa, CallEvent is roughly equivalent to NSInvocation.)
NOTE: For those familiar with Cocoa, CallEvent is roughly equivalent to
NSInvocation.
CallEvent should be used whenever there is logic dealing with function calls that does not care how the call occurred. Examples include checking that arguments satisfy preconditions (such as __attribute__((nonnull))), and attempting to inline a call.
CallEvent should be used whenever there is logic dealing with function calls
that does not care how the call occurred.
CallEvents are reference-counted objects managed by a CallEventManager. While there is no inherent issue with persisting them (say, in the state's GDM), they are intended for short-lived use, and can be recreated from CFGElements or StackFrameContexts fairly easily.
Examples include checking that arguments satisfy preconditions (such as
__attribute__((nonnull))), and attempting to inline a call.
CallEvents are reference-counted objects managed by a CallEventManager. While
there is no inherent issue with persisting them (say, in a ProgramState's GDM),
they are intended for short-lived use, and can be recreated from CFGElements or
non-top-level StackFrameContexts fairly easily.

View File

@ -0,0 +1,89 @@
The analyzer contains a number of checkers which can aid in debugging. Enable them by using the "-analyzer-checker=" flag, followed by the name of the checker.
General Analysis Dumpers
========================
These checkers are used to dump the results of various infrastructural analyses to stderr. Some checkers also have "view" variants, which will display a graph using a 'dot' format viewer (such as Graphviz on OS X) instead.
- debug.DumpCallGraph, debug.ViewCallGraph: Show the call graph generated for the current translation unit. This is used to determine the order in which to analyze functions when inlining is enabled.
- debug.DumpCFG, debug.ViewCFG: Show the CFG generated for each top-level function being analyzed.
- debug.DumpDominators: Shows the dominance tree for the CFG of each top-level function.
- debug.DumpLiveVars: Show the results of live variable analysis for each top-level function being analyzed.
Path Tracking
=============
These checkers print information about the path taken by the analyzer engine.
- debug.DumpCalls: Prints out every function or method call encountered during a path traversal. This is indented to show the call stack, but does NOT do any special handling of branches, meaning different paths could end up interleaved.
- debug.DumpTraversal: Prints the name of each branch statement encountered during a path traversal ("IfStmt", "WhileStmt", etc). Currently used to check whether the analysis engine is doing BFS or DFS.
State Checking
==============
These checkers will print out information about the analyzer state in the form of analysis warnings. They are intended for use with the -verify functionality in regression tests.
- debug.TaintTest: Prints out the word "tainted" for every expression that carries taint. At the time of this writing, taint was only introduced by the checks under experimental.security.taint.TaintPropagation; this checker may eventually move to the security.taint package.
- debug.ExprInspection: Responds to certain function calls, which are modeled after builtins. These function calls should affect the program state other than the evaluation of their arguments; to use them, you will need to declare them within your test file. The available functions are described below.
(FIXME: debug.ExprInspection should probably be renamed, since it no longer only inspects expressions.)
ExprInspection checks
---------------------
- void clang_analyzer_eval(bool);
Prints TRUE if the argument is known to have a non-zero value,
FALSE if the argument is known to have a zero or null value, and
UNKNOWN if the argument isn't sufficiently constrained on this path.
You can use this to test other values by using expressions like "x == 5".
Note that this functionality is currently DISABLED in inlined functions,
since different calls to the same inlined function could provide different
information, making it difficult to write proper -verify directives.
In C, the argument can be typed as 'int' or as '_Bool'.
Example usage:
clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
if (!x) return;
clang_analyzer_eval(x); // expected-warning{{TRUE}}
- void clang_analyzer_checkInlined(bool);
If a call occurs within an inlined function, prints TRUE or FALSE according to
the value of its argument. If a call occurs outside an inlined function,
nothing is printed.
The intended use of this checker is to assert that a function is inlined at
least once (by passing 'true' and expecting a warning), or to assert that a
function is never inlined (by passing 'false' and expecting no warning). The
argument is technically unnecessary but is intended to clarify intent.
You might wonder why we can't print TRUE if a function is ever inlined and
FALSE if it is not. The problem is that any inlined function could conceivably
also be analyzed as a top-level function (in which case both TRUE and FALSE
would be printed), depending on the value of the -analyzer-inlining option.
In C, the argument can be typed as 'int' or as '_Bool'.
Example usage:
int inlined() {
clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
return 42;
}
void topLevel() {
clang_analyzer_checkInlined(false); // no-warning (not inlined)
int value = inlined();
// This assertion will not be valid if the previous call was not inlined.
clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
}
Statistics
==========
The debug.Stats checker collects various information about the analysis of each function, such as how many blocks were reached and if the analyzer timed out.
There is also an additional -analyzer-stats flag, which enables various statistics within the analyzer engine. Note the Stats checker (which produces at least one bug report per function) may actually change the values reported by -analyzer-stats.

View File

@ -132,7 +132,7 @@ Treat subsequent input files as having type I<language>.
Specify the language standard to compile for.
=item B<-stdlib>=I<language>
=item B<-stdlib>=I<library>
Specify the C++ standard library to use; supported options are libstdc++ and
libc++.

View File

@ -0,0 +1,264 @@
#!/usr/bin/env python
# A tool to parse ASTMatchers.h and update the documentation in
# ../LibASTMatchersReference.html automatically. Run from the
# directory in which this file is located to update the docs.
import collections
import re
import urllib2
MATCHERS_FILE = '../../include/clang/ASTMatchers/ASTMatchers.h'
# Each matcher is documented in one row of the form:
# result | name | argA
# The subsequent row contains the documentation and is hidden by default,
# becoming visible via javascript when the user clicks the matcher name.
TD_TEMPLATE="""
<tr><td>%(result)s</td><td class="name" onclick="toggle('%(id)s')"><a name="%(id)sAnchor">%(name)s</a></td><td>%(args)s</td></tr>
<tr><td colspan="4" class="doc" id="%(id)s"><pre>%(comment)s</pre></td></tr>
"""
# We categorize the matchers into these three categories in the reference:
node_matchers = {}
narrowing_matchers = {}
traversal_matchers = {}
# We output multiple rows per matcher if the matcher can be used on multiple
# node types. Thus, we need a new id per row to control the documentation
# pop-up. ids[name] keeps track of those ids.
ids = collections.defaultdict(int)
# Cache for doxygen urls we have already verified.
doxygen_probes = {}
def esc(text):
"""Escape any html in the given text."""
text = re.sub(r'&', '&amp;', text)
text = re.sub(r'<', '&lt;', text)
text = re.sub(r'>', '&gt;', text)
def link_if_exists(m):
name = m.group(1)
url = 'http://clang.llvm.org/doxygen/classclang_1_1%s.html' % name
if url not in doxygen_probes:
try:
print 'Probing %s...' % url
urllib2.urlopen(url)
doxygen_probes[url] = True
except:
doxygen_probes[url] = False
if doxygen_probes[url]:
return r'Matcher&lt<a href="%s">%s</a>&gt;' % (url, name)
else:
return m.group(0)
text = re.sub(
r'Matcher&lt;([^\*&]+)&gt;', link_if_exists, text)
return text
def extract_result_types(comment):
"""Extracts a list of result types from the given comment.
We allow annotations in the comment of the matcher to specify what
nodes a matcher can match on. Those comments have the form:
Usable as: Any Matcher | (Matcher<T1>[, Matcher<t2>[, ...]])
Returns ['*'] in case of 'Any Matcher', or ['T1', 'T2', ...].
Returns the empty list if no 'Usable as' specification could be
parsed.
"""
result_types = []
m = re.search(r'Usable as: Any Matcher[\s\n]*$', comment, re.S)
if m:
return ['*']
while True:
m = re.match(r'^(.*)Matcher<([^>]+)>\s*,?[\s\n]*$', comment, re.S)
if not m:
if re.search(r'Usable as:\s*$', comment):
return result_types
else:
return None
result_types += [m.group(2)]
comment = m.group(1)
def strip_doxygen(comment):
"""Returns the given comment without \-escaped words."""
# If there is only a doxygen keyword in the line, delete the whole line.
comment = re.sub(r'^\\[^\s]+\n', r'', comment, flags=re.M)
# Delete the doxygen command and the following whitespace.
comment = re.sub(r'\\[^\s]+\s+', r'', comment)
return comment
def unify_arguments(args):
"""Gets rid of anything the user doesn't care about in the argument list."""
args = re.sub(r'internal::', r'', args)
args = re.sub(r'const\s+', r'', args)
args = re.sub(r'&', r' ', args)
args = re.sub(r'(^|\s)M\d?(\s)', r'\1Matcher<*>\2', args)
return args
def add_matcher(result_type, name, args, comment, is_dyncast=False):
"""Adds a matcher to one of our categories."""
if name == 'id':
# FIXME: Figure out whether we want to support the 'id' matcher.
return
matcher_id = '%s%d' % (name, ids[name])
ids[name] += 1
args = unify_arguments(args)
matcher_html = TD_TEMPLATE % {
'result': esc('Matcher<%s>' % result_type),
'name': name,
'args': esc(args),
'comment': esc(strip_doxygen(comment)),
'id': matcher_id,
}
if is_dyncast:
node_matchers[result_type + name] = matcher_html
# Use a heuristic to figure out whether a matcher is a narrowing or
# traversal matcher. By default, matchers that take other matchers as
# arguments (and are not node matchers) do traversal. We specifically
# exclude known narrowing matchers that also take other matchers as
# arguments.
elif ('Matcher<' not in args or
name in ['allOf', 'anyOf', 'anything', 'unless']):
narrowing_matchers[result_type + name] = matcher_html
else:
traversal_matchers[result_type + name] = matcher_html
def act_on_decl(declaration, comment, allowed_types):
"""Parse the matcher out of the given declaration and comment.
If 'allowed_types' is set, it contains a list of node types the matcher
can match on, as extracted from the static type asserts in the matcher
definition.
"""
if declaration.strip():
# Node matchers are defined by writing:
# VariadicDynCastAllOfMatcher<ResultType, ArgumentType> name;
m = re.match(r""".*VariadicDynCastAllOfMatcher\s*<
\s*([^\s,]+)\s*,
\s*([^\s>]+)\s*>
\s*([^\s;]+)\s*;\s*$""", declaration, flags=re.X)
if m:
result, inner, name = m.groups()
add_matcher(result, name, 'Matcher<%s>...' % inner,
comment, is_dyncast=True)
return
# Parse the various matcher definition macros.
m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)\(
(?:\s*([^\s,]+)\s*,)?
\s*([^\s,]+)\s*
(?:,\s*([^\s,]+)\s*
,\s*([^\s,]+)\s*)?
(?:,\s*([^\s,]+)\s*
,\s*([^\s,]+)\s*)?
\)\s*{\s*$""", declaration, flags=re.X)
if m:
p, n, result, name = m.groups()[1:5]
args = m.groups()[5:]
if not result:
if not allowed_types:
raise Exception('Did not find allowed result types for: %s' % name)
result_types = allowed_types
else:
result_types = [result]
if n not in ['', '2']:
raise Exception('Cannot parse "%s"' % declaration)
args = ', '.join('%s %s' % (args[i], args[i+1])
for i in range(0, len(args), 2) if args[i])
for result_type in result_types:
add_matcher(result_type, name, args, comment)
return
# Parse free standing matcher functions, like:
# Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) {
m = re.match(r"""^\s*(.*)\s+
([^\s\(]+)\s*\(
(.*)
\)\s*{""", declaration, re.X)
if m:
result, name, args = m.groups()
args = ', '.join(p.strip() for p in args.split(','))
m = re.match(r'.*\s+internal::Matcher<([^>]+)>$', result)
if m:
result_types = [m.group(1)]
else:
result_types = extract_result_types(comment)
if not result_types:
if not comment:
# Only overloads don't have their own doxygen comments; ignore those.
print 'Ignoring "%s"' % name
else:
print 'Cannot determine result type for "%s"' % name
else:
for result_type in result_types:
add_matcher(result_type, name, args, comment)
else:
print '*** Unparsable: "' + declaration + '" ***'
def sort_table(matcher_type, matcher_map):
"""Returns the sorted html table for the given row map."""
table = ''
for key in sorted(matcher_map.keys()):
table += matcher_map[key] + '\n'
return ('<!-- START_%(type)s_MATCHERS -->\n' +
'%(table)s' +
'<!--END_%(type)s_MATCHERS -->') % {
'type': matcher_type,
'table': table,
}
# Parse the ast matchers.
# We alternate between two modes:
# body = True: We parse the definition of a matcher. We need
# to parse the full definition before adding a matcher, as the
# definition might contain static asserts that specify the result
# type.
# body = False: We parse the comments and declaration of the matcher.
comment = ''
declaration = ''
allowed_types = []
body = False
for line in open(MATCHERS_FILE).read().splitlines():
if body:
if line.strip() and line[0] == '}':
if declaration:
act_on_decl(declaration, comment, allowed_types)
comment = ''
declaration = ''
allowed_types = []
body = False
else:
m = re.search(r'is_base_of<([^,]+), NodeType>', line)
if m and m.group(1):
allowed_types += [m.group(1)]
continue
if line.strip() and line.lstrip()[0] == '/':
comment += re.sub(r'/+\s?', '', line) + '\n'
else:
declaration += ' ' + line
if ((not line.strip()) or
line.rstrip()[-1] == ';' or
line.rstrip()[-1] == '{'):
if line.strip() and line.rstrip()[-1] == '{':
body = True
else:
act_on_decl(declaration, comment, allowed_types)
comment = ''
declaration = ''
allowed_types = []
node_matcher_table = sort_table('DECL', node_matchers)
narrowing_matcher_table = sort_table('NARROWING', narrowing_matchers)
traversal_matcher_table = sort_table('TRAVERSAL', traversal_matchers)
reference = open('../LibASTMatchersReference.html').read()
reference = re.sub(r'<!-- START_DECL_MATCHERS.*END_DECL_MATCHERS -->',
'%s', reference, flags=re.S) % node_matcher_table
reference = re.sub(r'<!-- START_NARROWING_MATCHERS.*END_NARROWING_MATCHERS -->',
'%s', reference, flags=re.S) % narrowing_matcher_table
reference = re.sub(r'<!-- START_TRAVERSAL_MATCHERS.*END_TRAVERSAL_MATCHERS -->',
'%s', reference, flags=re.S) % traversal_matcher_table
with open('../LibASTMatchersReference.html', 'w') as output:
output.write(reference)

View File

@ -39,7 +39,7 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const
BugReport *report = new BugReport(*BT, BT->getName(), N);
report->addRange(Callee->getSourceRange());
C.EmitReport(report);
C.emitReport(report);
}
}

View File

@ -29,7 +29,8 @@ target_link_libraries(clang-interpreter
clangStaticAnalyzerCheckers
clangStaticAnalyzerCore
clangAnalysis
clangRewrite
clangRewriteCore
clangRewriteFrontend
clangAST
clangParse
clangLex

View File

@ -20,7 +20,7 @@ LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
clangAnalysis.a clangRewrite.a \
clangAnalysis.a clangRewriteCore.a clangRewriteFrontend.a \
clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile

View File

@ -13,9 +13,9 @@
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/Module.h"
#include "llvm/ADT/OwningPtr.h"
@ -69,11 +69,12 @@ static int Execute(llvm::Module *Mod, char * const *envp) {
int main(int argc, const char **argv, char * const *envp) {
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
llvm::sys::Path Path = GetExecutablePath(argv[0]);
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, DiagClient);
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
"a.out", /*IsProduction=*/false, Diags);
TheDriver.setTitle("clang interpreter");

View File

@ -23,6 +23,34 @@
#include "clang-c/Platform.h"
#include "clang-c/CXString.h"
/**
* \brief The version constants for the libclang API.
* CINDEX_VERSION_MINOR should increase when there are API additions.
* CINDEX_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
*
* The policy about the libclang API was always to keep it source and ABI
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
#define CINDEX_VERSION_MINOR 6
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
+ ((minor) * 1))
#define CINDEX_VERSION CINDEX_VERSION_ENCODE( \
CINDEX_VERSION_MAJOR, \
CINDEX_VERSION_MINOR )
#define CINDEX_VERSION_STRINGIZE_(major, minor) \
#major"."#minor
#define CINDEX_VERSION_STRINGIZE(major, minor) \
CINDEX_VERSION_STRINGIZE_(major, minor)
#define CINDEX_VERSION_STRING CINDEX_VERSION_STRINGIZE( \
CINDEX_VERSION_MAJOR, \
CINDEX_VERSION_MINOR)
#ifdef __cplusplus
extern "C" {
#endif
@ -383,7 +411,7 @@ CINDEX_LINKAGE unsigned clang_equalRanges(CXSourceRange range1,
CXSourceRange range2);
/**
* \brief Returns non-zero if \arg range is null.
* \brief Returns non-zero if \p range is null.
*/
CINDEX_LINKAGE int clang_Range_isNull(CXSourceRange range);
@ -1035,13 +1063,15 @@ enum CXTranslationUnit_Flags {
* code-completion operations.
*/
CXTranslationUnit_CacheCompletionResults = 0x08,
/**
* \brief DEPRECATED: Enable precompiled preambles in C++.
* \brief Used to indicate that the translation unit will be serialized with
* \c clang_saveTranslationUnit.
*
* Note: this is a *temporary* option that is available only while
* we are testing C++ precompiled preamble support. It is deprecated.
* This option is typically used when parsing a header with the intent of
* producing a precompiled header.
*/
CXTranslationUnit_CXXPrecompiledPreamble = 0x10,
CXTranslationUnit_ForSerialization = 0x10,
/**
* \brief DEPRECATED: Enabled chained precompiled preambles in C++.
@ -1904,9 +1934,10 @@ enum CXCursorKind {
*/
CXCursor_ReturnStmt = 214,
/** \brief A GNU inline assembly statement extension.
/** \brief A GCC inline assembly statement extension.
*/
CXCursor_AsmStmt = 215,
CXCursor_GCCAsmStmt = 215,
CXCursor_AsmStmt = CXCursor_GCCAsmStmt,
/** \brief Objective-C's overall \@try-\@catch-\@finally statement.
*/
@ -2009,7 +2040,15 @@ enum CXCursorKind {
CXCursor_MacroInstantiation = CXCursor_MacroExpansion,
CXCursor_InclusionDirective = 503,
CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective,
CXCursor_LastPreprocessing = CXCursor_InclusionDirective
CXCursor_LastPreprocessing = CXCursor_InclusionDirective,
/* Extra Declarations */
/**
* \brief A module import declaration.
*/
CXCursor_ModuleImportDecl = 600,
CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl,
CXCursor_LastExtraDecl = CXCursor_ModuleImportDecl
};
/**
@ -2040,7 +2079,8 @@ typedef struct {
* \brief A comment AST node.
*/
typedef struct {
const void *Data;
const void *ASTNode;
CXTranslationUnit TranslationUnit;
} CXComment;
/**
@ -2068,9 +2108,9 @@ CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);
CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor);
/**
* \brief Returns non-zero if \arg cursor is null.
* \brief Returns non-zero if \p cursor is null.
*/
CINDEX_LINKAGE int clang_Cursor_isNull(CXCursor);
CINDEX_LINKAGE int clang_Cursor_isNull(CXCursor cursor);
/**
* \brief Compute a hash value for the given cursor.
@ -2585,6 +2625,7 @@ enum CXCallingConv {
CXCallingConv_X86Pascal = 5,
CXCallingConv_AAPCS = 6,
CXCallingConv_AAPCS_VFP = 7,
CXCallingConv_PnaclCall = 8,
CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
@ -3163,6 +3204,12 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
*/
CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C);
/**
* \brief Given a cursor pointing to an ObjC message, returns the CXType of the
* receiver.
*/
CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C);
/**
* \brief Given a cursor that represents a declaration, return the associated
* comment's source range. The range may include multiple consecutive comments
@ -3190,6 +3237,65 @@ CINDEX_LINKAGE CXString clang_Cursor_getBriefCommentText(CXCursor C);
*/
CINDEX_LINKAGE CXComment clang_Cursor_getParsedComment(CXCursor C);
/**
* @}
*/
/**
* \defgroup CINDEX_MODULE Module introspection
*
* The functions in this group provide access to information about modules.
*
* @{
*/
typedef void *CXModule;
/**
* \brief Given a CXCursor_ModuleImportDecl cursor, return the associated module.
*/
CINDEX_LINKAGE CXModule clang_Cursor_getModule(CXCursor C);
/**
* \param Module a module object.
*
* \returns the parent of a sub-module or NULL if the given module is top-level,
* e.g. for 'std.vector' it will return the 'std' module.
*/
CINDEX_LINKAGE CXModule clang_Module_getParent(CXModule Module);
/**
* \param Module a module object.
*
* \returns the name of the module, e.g. for the 'std.vector' sub-module it
* will return "vector".
*/
CINDEX_LINKAGE CXString clang_Module_getName(CXModule Module);
/**
* \param Module a module object.
*
* \returns the full name of the module, e.g. "std.vector".
*/
CINDEX_LINKAGE CXString clang_Module_getFullName(CXModule Module);
/**
* \param Module a module object.
*
* \returns the number of top level headers associated with this module.
*/
CINDEX_LINKAGE unsigned clang_Module_getNumTopLevelHeaders(CXModule Module);
/**
* \param Module a module object.
*
* \param Index top level header index (zero-based).
*
* \returns the specified top level header associated with the module.
*/
CINDEX_LINKAGE
CXFile clang_Module_getTopLevelHeader(CXModule Module, unsigned Index);
/**
* @}
*/
@ -3272,7 +3378,7 @@ enum CXCommentKind {
* \brief A \\param or \\arg command that describes the function parameter
* (name, passing direction, description).
*
* \brief For example: \\param [in] ParamName description.
* For example: \\param [in] ParamName description.
*/
CXComment_ParamCommand = 7,
@ -3280,7 +3386,7 @@ enum CXCommentKind {
* \brief A \\tparam command that describes a template parameter (name and
* description).
*
* \brief For example: \\tparam T description.
* For example: \\tparam T description.
*/
CXComment_TParamCommand = 8,
@ -3379,7 +3485,7 @@ CINDEX_LINKAGE unsigned clang_Comment_getNumChildren(CXComment Comment);
/**
* \param Comment AST node of any kind.
*
* \param ArgIdx argument index (zero-based).
* \param ChildIdx child index (zero-based).
*
* \returns the specified child of the AST node.
*/
@ -3692,14 +3798,11 @@ CINDEX_LINKAGE CXString clang_FullComment_getAsHTML(CXComment Comment);
* A Relax NG schema for the XML can be found in comment-xml-schema.rng file
* inside clang source tree.
*
* \param TU the translation unit \c Comment belongs to.
*
* \param Comment a \c CXComment_FullComment AST node.
*
* \returns string containing an XML document.
*/
CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXTranslationUnit TU,
CXComment Comment);
CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment);
/**
* @}
@ -4323,8 +4426,7 @@ clang_getCompletionAnnotation(CXCompletionString completion_string,
* \param completion_string The code completion string whose parent is
* being queried.
*
* \param kind If non-NULL, will be set to the kind of the parent context,
* or CXCursor_NotImplemented if there is no context.
* \param kind DEPRECATED: always set to CXCursor_NotImplemented if non-NULL.
*
* \returns The name of the completion parent, e.g., "NSObject" if
* the completion string represents a method in the NSObject class.
@ -4917,22 +5019,35 @@ typedef struct {
CXFile file;
int isImport;
int isAngled;
/**
* \brief Non-zero if the directive was automatically turned into a module
* import.
*/
int isModuleImport;
} CXIdxIncludedFileInfo;
/**
* \brief Data for IndexerCallbacks#importedASTFile.
*/
typedef struct {
/**
* \brief Top level AST file containing the imported PCH, module or submodule.
*/
CXFile file;
/**
* \brief Location where the file is imported. It is useful mostly for
* modules.
* \brief The imported module or NULL if the AST file is a PCH.
*/
CXModule module;
/**
* \brief Location where the file is imported. Applicable only for modules.
*/
CXIdxLoc loc;
/**
* \brief Non-zero if the AST file is a module otherwise it's a PCH.
* \brief Non-zero if an inclusion directive was automatically turned into
* a module import. Applicable only for modules.
*/
int isModule;
int isImplicit;
} CXIdxImportedASTFileInfo;
typedef enum {
@ -4965,7 +5080,8 @@ typedef enum {
CXIdxEntity_CXXConstructor = 22,
CXIdxEntity_CXXDestructor = 23,
CXIdxEntity_CXXConversionFunction = 24,
CXIdxEntity_CXXTypeAlias = 25
CXIdxEntity_CXXTypeAlias = 25,
CXIdxEntity_CXXInterface = 26
} CXIdxEntityKind;
@ -5183,8 +5299,8 @@ typedef struct {
*
* AST files will not get indexed (there will not be callbacks to index all
* the entities in an AST file). The recommended action is that, if the AST
* file is not already indexed, to block further indexing and initiate a new
* indexing job specific to the AST file.
* file is not already indexed, to initiate a new indexing job specific to
* the AST file.
*/
CXIdxClientASTFile (*importedASTFile)(CXClientData client_data,
const CXIdxImportedASTFileInfo *);

View File

@ -12,6 +12,7 @@
#include "clang/ARCMigrate/FileRemapper.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Basic/SourceLocation.h"
namespace clang {
class ASTContext;
@ -51,7 +52,7 @@ bool applyTransformations(CompilerInvocation &origCI,
DiagnosticConsumer *DiagClient);
/// \brief Applies automatic modifications and produces temporary files
/// and metadata into the \arg outputDir path.
/// and metadata into the \p outputDir path.
///
/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
/// even if the migrator can fix them, but the function will still return false
@ -68,7 +69,7 @@ bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
bool emitPremigrationARCErrors,
StringRef plistOut);
/// \brief Get the set of file remappings from the \arg outputDir path that
/// \brief Get the set of file remappings from the \p outputDir path that
/// migrateWithTemporaryFiles produced.
///
/// \returns false if no error is produced, true otherwise.

View File

@ -19,12 +19,14 @@ namespace clang {
class CXXRecordDecl;
class DeclGroupRef;
class HandleTagDeclDefinition;
class PPMutationListener;
class ASTMutationListener;
class ASTDeserializationListener; // layering violation because void* is ugly
class SemaConsumer; // layering violation required for safe SemaConsumer
class TagDecl;
class VarDecl;
class FunctionDecl;
class ImportDecl;
/// ASTConsumer - This is an abstract interface that should be implemented by
/// clients that read ASTs. This abstraction layer allows the client to be
@ -79,6 +81,11 @@ class ASTConsumer {
/// The default implementation ignored them.
virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
/// \brief Handle an ImportDecl that was implicitly created due to an
/// inclusion directive.
/// The default implementation passes it to HandleTopLevelDecl.
virtual void HandleImplicitImportDecl(ImportDecl *D);
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
/// unit to notify the consumer that the given tentative definition should be
/// completed.
@ -105,6 +112,11 @@ class ASTConsumer {
/// it was actually used.
virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
/// \brief If the consumer is interested in preprocessor entities getting
/// modified after their initial creation, it should return a pointer to
/// a PPMutationListener here.
virtual PPMutationListener *GetPPMutationListener() { return 0; }
/// \brief If the consumer is interested in entities getting modified after
/// their initial creation, it should return a pointer to
/// an ASTMutationListener here.
@ -118,9 +130,6 @@ class ASTConsumer {
/// PrintStats - If desired, print any statistics.
virtual void PrintStats() {}
// Support isa/cast/dyn_cast
static bool classof(const ASTConsumer *) { return true; }
};
} // end namespace clang.

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,8 @@
#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
#include "clang/Basic/SourceLocation.h"
namespace clang {
class Decl;
class DeclContext;

View File

@ -107,9 +107,6 @@ class Attr {
// Pretty print this attribute.
virtual void printPretty(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const = 0;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *) { return true; }
};
class InheritableAttr : public Attr {
@ -125,7 +122,6 @@ class InheritableAttr : public Attr {
static bool classof(const Attr *A) {
return A->getKind() <= attr::LAST_INHERITABLE;
}
static bool classof(const InheritableAttr *) { return true; }
};
class InheritableParamAttr : public InheritableAttr {
@ -139,7 +135,6 @@ class InheritableParamAttr : public InheritableAttr {
static bool classof(const Attr *A) {
return A->getKind() <= attr::LAST_INHERITABLE_PARAM;
}
static bool classof(const InheritableParamAttr *) { return true; }
};
#include "clang/AST/Attrs.inc"

View File

@ -206,6 +206,8 @@ PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy)
// unknown type, most notably explicit casts.
PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy)
PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy)
// The type of a cast which, in ARC, would normally require a
// __bridge, but which might be okay depending on the immediate
// context.

View File

@ -20,3 +20,15 @@ clang_tablegen(CommentNodes.inc -gen-clang-comment-nodes
SOURCE ../Basic/CommentNodes.td
TARGET ClangCommentNodes)
clang_tablegen(CommentHTMLTags.inc -gen-clang-comment-html-tags
SOURCE CommentHTMLTags.td
TARGET ClangCommentHTMLTags)
clang_tablegen(CommentHTMLTagsProperties.inc -gen-clang-comment-html-tags-properties
SOURCE CommentHTMLTags.td
TARGET ClangCommentHTMLTagsProperties)
clang_tablegen(CommentCommandInfo.inc -gen-clang-comment-command-info
SOURCE CommentCommands.td
TARGET ClangCommentCommandInfo)

View File

@ -19,7 +19,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include <list>
@ -271,15 +271,14 @@ struct UniqueVirtualMethod {
/// pair is the virtual method that overrides it (including the
/// subobject in which that virtual function occurs).
class OverridingMethods {
llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
Overrides;
typedef SmallVector<UniqueVirtualMethod, 4> ValuesT;
typedef llvm::MapVector<unsigned, ValuesT> MapType;
MapType Overrides;
public:
// Iterate over the set of subobjects that have overriding methods.
typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
::iterator iterator;
typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
::const_iterator const_iterator;
typedef MapType::iterator iterator;
typedef MapType::const_iterator const_iterator;
iterator begin() { return Overrides.begin(); }
const_iterator begin() const { return Overrides.begin(); }
iterator end() { return Overrides.end(); }
@ -357,8 +356,8 @@ class OverridingMethods {
/// 0 represents the virtua base class subobject of that type, while
/// subobject numbers greater than 0 refer to non-virtual base class
/// subobjects of that type.
class CXXFinalOverriderMap
: public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { };
class CXXFinalOverriderMap
: public llvm::MapVector<const CXXMethodDecl *, OverridingMethods> { };
/// \brief A set of all the primary bases for a class.
class CXXIndirectPrimaryBaseSet

View File

@ -276,6 +276,7 @@ class CanProxyBase {
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isInterfaceType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)

View File

@ -164,8 +164,8 @@ namespace clang {
QuantityType getQuantity() const { return Quantity; }
/// RoundUpToAlignment - Returns the next integer (mod 2**64) that is
/// greater than or equal to this quantity and is a multiple of \arg
/// Align. Align must be non-zero.
/// greater than or equal to this quantity and is a multiple of \p Align.
/// Align must be non-zero.
CharUnits RoundUpToAlignment(const CharUnits &Align) {
return CharUnits(llvm::RoundUpToAlignment(Quantity,
Align.Quantity));

View File

@ -16,6 +16,8 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/Type.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
@ -25,7 +27,7 @@ class ParmVarDecl;
class TemplateParameterList;
namespace comments {
class FullComment;
/// Any part of the comment.
/// Abstract class.
class Comment {
@ -74,8 +76,9 @@ class Comment {
unsigned : NumInlineContentCommentBits;
unsigned RenderKind : 2;
unsigned CommandID : 8;
};
enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 1 };
enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 10 };
class HTMLStartTagCommentBitfields {
friend class HTMLStartTagComment;
@ -101,10 +104,19 @@ class Comment {
};
enum { NumParagraphCommentBits = NumCommentBits + 2 };
class BlockCommandCommentBitfields {
friend class BlockCommandComment;
unsigned : NumCommentBits;
unsigned CommandID : 8;
};
enum { NumBlockCommandCommentBits = NumCommentBits + 8 };
class ParamCommandCommentBitfields {
friend class ParamCommandComment;
unsigned : NumCommentBits;
unsigned : NumBlockCommandCommentBits;
/// Parameter passing direction, see ParamCommandComment::PassDirection.
unsigned Direction : 2;
@ -112,7 +124,7 @@ class Comment {
/// True if direction was specified explicitly in the comment.
unsigned IsDirectionExplicit : 1;
};
enum { NumParamCommandCommentBits = 11 };
enum { NumParamCommandCommentBits = NumBlockCommandCommentBits + 3 };
union {
CommentBitfields CommentBits;
@ -121,6 +133,7 @@ class Comment {
InlineCommandCommentBitfields InlineCommandCommentBits;
HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
ParagraphCommentBitfields ParagraphCommentBits;
BlockCommandCommentBitfields BlockCommandCommentBits;
ParamCommandCommentBitfields ParamCommandCommentBits;
};
@ -158,10 +171,9 @@ class Comment {
const char *getCommentKindName() const;
LLVM_ATTRIBUTE_USED void dump() const;
LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
void dump(llvm::raw_ostream &OS, SourceManager *SM) const;
static bool classof(const Comment *) { return true; }
LLVM_ATTRIBUTE_USED void dump(const ASTContext &Context) const;
void dump(llvm::raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM) const;
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
@ -204,8 +216,6 @@ class InlineContentComment : public Comment {
C->getCommentKind() <= LastInlineContentCommentConstant;
}
static bool classof(const InlineContentComment *) { return true; }
void addTrailingNewline() {
InlineContentCommentBits.HasTrailingNewline = 1;
}
@ -232,8 +242,6 @@ class TextComment : public InlineContentComment {
return C->getCommentKind() == TextCommentKind;
}
static bool classof(const TextComment *) { return true; }
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@ -273,35 +281,35 @@ class InlineCommandComment : public InlineContentComment {
};
protected:
/// Command name.
StringRef Name;
/// Command arguments.
llvm::ArrayRef<Argument> Args;
public:
InlineCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name,
unsigned CommandID,
RenderKind RK,
llvm::ArrayRef<Argument> Args) :
InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd),
Name(Name), Args(Args) {
Args(Args) {
InlineCommandCommentBits.RenderKind = RK;
InlineCommandCommentBits.CommandID = CommandID;
}
static bool classof(const Comment *C) {
return C->getCommentKind() == InlineCommandCommentKind;
}
static bool classof(const InlineCommandComment *) { return true; }
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
StringRef getCommandName() const {
return Name;
unsigned getCommandID() const {
return InlineCommandCommentBits.CommandID;
}
StringRef getCommandName(const CommandTraits &Traits) const {
return Traits.getCommandInfo(getCommandID())->Name;
}
SourceRange getCommandNameRange() const {
@ -352,8 +360,6 @@ class HTMLTagComment : public InlineContentComment {
C->getCommentKind() <= LastHTMLTagCommentConstant;
}
static bool classof(const HTMLTagComment *) { return true; }
StringRef getTagName() const LLVM_READONLY { return TagName; }
SourceRange getTagNameSourceRange() const LLVM_READONLY {
@ -419,8 +425,6 @@ class HTMLStartTagComment : public HTMLTagComment {
return C->getCommentKind() == HTMLStartTagCommentKind;
}
static bool classof(const HTMLStartTagComment *) { return true; }
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@ -476,8 +480,6 @@ class HTMLEndTagComment : public HTMLTagComment {
return C->getCommentKind() == HTMLEndTagCommentKind;
}
static bool classof(const HTMLEndTagComment *) { return true; }
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@ -498,8 +500,6 @@ class BlockContentComment : public Comment {
return C->getCommentKind() >= FirstBlockContentCommentConstant &&
C->getCommentKind() <= LastBlockContentCommentConstant;
}
static bool classof(const BlockContentComment *) { return true; }
};
/// A single paragraph that contains inline content.
@ -529,8 +529,6 @@ class ParagraphComment : public BlockContentComment {
return C->getCommentKind() == ParagraphCommentKind;
}
static bool classof(const ParagraphComment *) { return true; }
child_iterator child_begin() const {
return reinterpret_cast<child_iterator>(Content.begin());
}
@ -566,9 +564,6 @@ class BlockCommandComment : public BlockContentComment {
};
protected:
/// Command name.
StringRef Name;
/// Word-like arguments.
llvm::ArrayRef<Argument> Args;
@ -578,21 +573,21 @@ class BlockCommandComment : public BlockContentComment {
BlockCommandComment(CommentKind K,
SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) :
unsigned CommandID) :
BlockContentComment(K, LocBegin, LocEnd),
Name(Name),
Paragraph(NULL) {
setLocation(getCommandNameRange().getBegin());
setLocation(getCommandNameBeginLoc());
BlockCommandCommentBits.CommandID = CommandID;
}
public:
BlockCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) :
unsigned CommandID) :
BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
Name(Name),
Paragraph(NULL) {
setLocation(getCommandNameRange().getBegin());
setLocation(getCommandNameBeginLoc());
BlockCommandCommentBits.CommandID = CommandID;
}
static bool classof(const Comment *C) {
@ -600,8 +595,6 @@ class BlockCommandComment : public BlockContentComment {
C->getCommentKind() <= LastBlockCommandCommentConstant;
}
static bool classof(const BlockCommandComment *) { return true; }
child_iterator child_begin() const {
return reinterpret_cast<child_iterator>(&Paragraph);
}
@ -610,12 +603,21 @@ class BlockCommandComment : public BlockContentComment {
return reinterpret_cast<child_iterator>(&Paragraph + 1);
}
StringRef getCommandName() const {
return Name;
unsigned getCommandID() const {
return BlockCommandCommentBits.CommandID;
}
SourceRange getCommandNameRange() const {
return SourceRange(getLocStart().getLocWithOffset(1),
StringRef getCommandName(const CommandTraits &Traits) const {
return Traits.getCommandInfo(getCommandID())->Name;
}
SourceLocation getCommandNameBeginLoc() const {
return getLocStart().getLocWithOffset(1);
}
SourceRange getCommandNameRange(const CommandTraits &Traits) const {
StringRef Name = getCommandName(Traits);
return SourceRange(getCommandNameBeginLoc(),
getLocStart().getLocWithOffset(1 + Name.size()));
}
@ -667,8 +669,9 @@ class ParamCommandComment : public BlockCommandComment {
ParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) :
BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, Name),
unsigned CommandID) :
BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
CommandID),
ParamIndex(InvalidParamIndex) {
ParamCommandCommentBits.Direction = In;
ParamCommandCommentBits.IsDirectionExplicit = false;
@ -678,8 +681,6 @@ class ParamCommandComment : public BlockCommandComment {
return C->getCommentKind() == ParamCommandCommentKind;
}
static bool classof(const ParamCommandComment *) { return true; }
enum PassDirection {
In,
Out,
@ -705,7 +706,9 @@ class ParamCommandComment : public BlockCommandComment {
return getNumArgs() > 0;
}
StringRef getParamName() const {
StringRef getParamName(const FullComment *FC) const;
StringRef getParamNameAsWritten() const {
return Args[0].Text;
}
@ -748,21 +751,21 @@ class TParamCommandComment : public BlockCommandComment {
public:
TParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) :
BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, Name)
unsigned CommandID) :
BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID)
{ }
static bool classof(const Comment *C) {
return C->getCommentKind() == TParamCommandCommentKind;
}
static bool classof(const TParamCommandComment *) { return true; }
bool hasParamName() const {
return getNumArgs() > 0;
}
StringRef getParamName() const {
StringRef getParamName(const FullComment *FC) const;
StringRef getParamNameAsWritten() const {
return Args[0].Text;
}
@ -807,8 +810,6 @@ class VerbatimBlockLineComment : public Comment {
return C->getCommentKind() == VerbatimBlockLineCommentKind;
}
static bool classof(const VerbatimBlockLineComment *) { return true; }
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@ -830,17 +831,15 @@ class VerbatimBlockComment : public BlockCommandComment {
public:
VerbatimBlockComment(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) :
unsigned CommandID) :
BlockCommandComment(VerbatimBlockCommentKind,
LocBegin, LocEnd, Name)
LocBegin, LocEnd, CommandID)
{ }
static bool classof(const Comment *C) {
return C->getCommentKind() == VerbatimBlockCommentKind;
}
static bool classof(const VerbatimBlockComment *) { return true; }
child_iterator child_begin() const {
return reinterpret_cast<child_iterator>(Lines.begin());
}
@ -882,12 +881,12 @@ class VerbatimLineComment : public BlockCommandComment {
public:
VerbatimLineComment(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name,
unsigned CommandID,
SourceLocation TextBegin,
StringRef Text) :
BlockCommandComment(VerbatimLineCommentKind,
LocBegin, LocEnd,
Name),
CommandID),
Text(Text),
TextBegin(TextBegin)
{ }
@ -896,8 +895,6 @@ class VerbatimLineComment : public BlockCommandComment {
return C->getCommentKind() == VerbatimLineCommentKind;
}
static bool classof(const VerbatimLineComment *) { return true; }
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@ -913,23 +910,34 @@ class VerbatimLineComment : public BlockCommandComment {
/// Information about the declaration, useful to clients of FullComment.
struct DeclInfo {
/// Declaration the comment is attached to. Should not be NULL.
const Decl *ThisDecl;
/// Parameters that can be referenced by \\param if \c ThisDecl is something
/// Declaration the comment is actually attached to (in the source).
/// Should not be NULL.
const Decl *CommentDecl;
/// CurrentDecl is the declaration with which the FullComment is associated.
///
/// It can be different from \c CommentDecl. It happens when we we decide
/// that the comment originally attached to \c CommentDecl is fine for
/// \c CurrentDecl too (for example, for a redeclaration or an overrider of
/// \c CommentDecl).
///
/// The information in the DeclInfo corresponds to CurrentDecl.
const Decl *CurrentDecl;
/// Parameters that can be referenced by \\param if \c CommentDecl is something
/// that we consider a "function".
ArrayRef<const ParmVarDecl *> ParamVars;
/// Function result type if \c ThisDecl is something that we consider
/// Function result type if \c CommentDecl is something that we consider
/// a "function".
QualType ResultType;
/// Template parameters that can be referenced by \\tparam if \c ThisDecl is
/// Template parameters that can be referenced by \\tparam if \c CommentDecl is
/// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
/// true).
const TemplateParameterList *TemplateParameters;
/// A simplified description of \c ThisDecl kind that should be good enough
/// A simplified description of \c CommentDecl kind that should be good enough
/// for documentation rendering purposes.
enum DeclKind {
/// Everything else not explicitly mentioned below.
@ -942,7 +950,9 @@ struct DeclInfo {
/// \li member function,
/// \li member function template,
/// \li member function template specialization,
/// \li ObjC method.
/// \li ObjC method,
/// \li a typedef for a function pointer, member function pointer,
/// ObjC block.
FunctionKind,
/// Something that we consider a "class":
@ -968,7 +978,7 @@ struct DeclInfo {
EnumKind
};
/// What kind of template specialization \c ThisDecl is.
/// What kind of template specialization \c CommentDecl is.
enum TemplateDeclKind {
NotTemplate,
Template,
@ -976,24 +986,24 @@ struct DeclInfo {
TemplatePartialSpecialization
};
/// If false, only \c ThisDecl is valid.
/// If false, only \c CommentDecl is valid.
unsigned IsFilled : 1;
/// Simplified kind of \c ThisDecl, see\c DeclKind enum.
/// Simplified kind of \c CommentDecl, see \c DeclKind enum.
unsigned Kind : 3;
/// Is \c ThisDecl a template declaration.
/// Is \c CommentDecl a template declaration.
unsigned TemplateKind : 2;
/// Is \c ThisDecl an ObjCMethodDecl.
/// Is \c CommentDecl an ObjCMethodDecl.
unsigned IsObjCMethod : 1;
/// Is \c ThisDecl a non-static member function of C++ class or
/// Is \c CommentDecl a non-static member function of C++ class or
/// instance method of ObjC class.
/// Can be true only if \c IsFunctionDecl is true.
unsigned IsInstanceMethod : 1;
/// Is \c ThisDecl a static member function of C++ class or
/// Is \c CommentDecl a static member function of C++ class or
/// class method of ObjC class.
/// Can be true only if \c IsFunctionDecl is true.
unsigned IsClassMethod : 1;
@ -1012,7 +1022,6 @@ struct DeclInfo {
/// A full comment attached to a declaration, contains block content.
class FullComment : public Comment {
llvm::ArrayRef<BlockContentComment *> Blocks;
DeclInfo *ThisDeclInfo;
public:
@ -1031,27 +1040,31 @@ class FullComment : public Comment {
return C->getCommentKind() == FullCommentKind;
}
static bool classof(const FullComment *) { return true; }
child_iterator child_begin() const {
return reinterpret_cast<child_iterator>(Blocks.begin());
}
child_iterator child_end() const {
return reinterpret_cast<child_iterator>(Blocks.end());
return reinterpret_cast<child_iterator>(Blocks.end());
}
const Decl *getDecl() const LLVM_READONLY {
return ThisDeclInfo->ThisDecl;
return ThisDeclInfo->CommentDecl;
}
const DeclInfo *getDeclInfo() const LLVM_READONLY {
if (!ThisDeclInfo->IsFilled)
ThisDeclInfo->fill();
return ThisDeclInfo;
}
DeclInfo *getThisDeclInfo() const LLVM_READONLY {
return ThisDeclInfo;
}
llvm::ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
};
} // end namespace comments
} // end namespace clang

View File

@ -44,8 +44,7 @@ class BriefParser {
public:
BriefParser(Lexer &L, const CommandTraits &Traits);
/// Return \\brief paragraph, if it exists; otherwise return the first
/// paragraph.
/// Return the best "brief description" we can find.
std::string Parse();
};

View File

@ -19,135 +19,131 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
namespace comments {
/// This class provides informaiton about commands that can be used
/// in comments.
class CommandTraits {
public:
CommandTraits() { }
/// \brief Information about a single command.
///
/// When reordering, adding or removing members please update the corresponding
/// TableGen backend.
struct CommandInfo {
unsigned getID() const {
return ID;
}
/// \brief Check if a given command is a verbatim-like block command.
const char *Name;
/// Name of the command that ends the verbatim block.
const char *EndCommandName;
unsigned ID : 8;
/// Number of word-like arguments for a given block command, except for
/// \\param and \\tparam commands -- these have special argument parsers.
unsigned NumArgs : 4;
/// True if this command is a inline command (of any kind).
unsigned IsInlineCommand : 1;
/// True if this command is a block command (of any kind).
unsigned IsBlockCommand : 1;
/// True if this command is introducing a brief documentation
/// paragraph (\\brief or an alias).
unsigned IsBriefCommand : 1;
/// True if this command is \\returns or an alias.
unsigned IsReturnsCommand : 1;
/// True if this command is introducing documentation for a function
/// parameter (\\param or an alias).
unsigned IsParamCommand : 1;
/// True if this command is introducing documentation for
/// a template parameter (\\tparam or an alias).
unsigned IsTParamCommand : 1;
/// True if this command is \\deprecated or an alias.
unsigned IsDeprecatedCommand : 1;
/// True if we don't want to warn about this command being passed an empty
/// paragraph. Meaningful only for block commands.
unsigned IsEmptyParagraphAllowed : 1;
/// \brief True if this command is a verbatim-like block command.
///
/// A verbatim-like block command eats every character (except line starting
/// decorations) until matching end command is seen or comment end is hit.
///
/// \param StartName name of the command that starts the verbatim block.
/// \param [out] EndName name of the command that ends the verbatim block.
///
/// \returns true if a given command is a verbatim block command.
bool isVerbatimBlockCommand(StringRef StartName, StringRef &EndName) const;
unsigned IsVerbatimBlockCommand : 1;
/// \brief Register a new verbatim block command.
void addVerbatimBlockCommand(StringRef StartName, StringRef EndName);
/// \brief True if this command is an end command for a verbatim-like block.
unsigned IsVerbatimBlockEndCommand : 1;
/// \brief Check if a given command is a verbatim line command.
/// \brief True if this command is a verbatim line command.
///
/// A verbatim-like line command eats everything until a newline is seen or
/// comment end is hit.
bool isVerbatimLineCommand(StringRef Name) const;
unsigned IsVerbatimLineCommand : 1;
/// \brief Check if a given command is a command that contains a declaration
/// for the entity being documented.
/// \brief True if this command contains a declaration for the entity being
/// documented.
///
/// For example:
/// \code
/// \fn void f(int a);
/// \endcode
bool isDeclarationCommand(StringRef Name) const;
unsigned IsDeclarationCommand : 1;
/// \brief Register a new verbatim line command.
void addVerbatimLineCommand(StringRef Name);
/// \brief Check if a given command is a block command (of any kind).
bool isBlockCommand(StringRef Name) const;
/// \brief Check if a given command is introducing documentation for
/// a function parameter (\\param or an alias).
bool isParamCommand(StringRef Name) const;
/// \brief Check if a given command is introducing documentation for
/// a template parameter (\\tparam or an alias).
bool isTParamCommand(StringRef Name) const;
/// \brief Check if a given command is introducing a brief documentation
/// paragraph (\\brief or an alias).
bool isBriefCommand(StringRef Name) const;
/// \brief Check if a given command is \\brief or an alias.
bool isReturnsCommand(StringRef Name) const;
/// \returns the number of word-like arguments for a given block command,
/// except for \\param and \\tparam commands -- these have special argument
/// parsers.
unsigned getBlockCommandNumArgs(StringRef Name) const;
/// \brief Check if a given command is a inline command (of any kind).
bool isInlineCommand(StringRef Name) const;
private:
struct VerbatimBlockCommand {
StringRef StartName;
StringRef EndName;
};
typedef SmallVector<VerbatimBlockCommand, 4> VerbatimBlockCommandVector;
/// Registered additional verbatim-like block commands.
VerbatimBlockCommandVector VerbatimBlockCommands;
struct VerbatimLineCommand {
StringRef Name;
};
typedef SmallVector<VerbatimLineCommand, 4> VerbatimLineCommandVector;
/// Registered verbatim-like line commands.
VerbatimLineCommandVector VerbatimLineCommands;
/// \brief True if this command is unknown. This \c CommandInfo object was
/// created during parsing.
unsigned IsUnknownCommand : 1;
};
inline bool CommandTraits::isBlockCommand(StringRef Name) const {
return isBriefCommand(Name) || isReturnsCommand(Name) ||
isParamCommand(Name) || isTParamCommand(Name) ||
llvm::StringSwitch<bool>(Name)
.Case("author", true)
.Case("authors", true)
.Case("pre", true)
.Case("post", true)
.Default(false);
}
/// This class provides information about commands that can be used
/// in comments.
class CommandTraits {
public:
CommandTraits(llvm::BumpPtrAllocator &Allocator);
inline bool CommandTraits::isParamCommand(StringRef Name) const {
return Name == "param";
}
/// \returns a CommandInfo object for a given command name or
/// NULL if no CommandInfo object exists for this command.
const CommandInfo *getCommandInfoOrNULL(StringRef Name) const;
inline bool CommandTraits::isTParamCommand(StringRef Name) const {
return Name == "tparam" || // Doxygen
Name == "templatefield"; // HeaderDoc
}
const CommandInfo *getCommandInfo(StringRef Name) const {
if (const CommandInfo *Info = getCommandInfoOrNULL(Name))
return Info;
llvm_unreachable("the command should be known");
}
inline bool CommandTraits::isBriefCommand(StringRef Name) const {
return Name == "brief" || Name == "short";
}
const CommandInfo *getCommandInfo(unsigned CommandID) const;
inline bool CommandTraits::isReturnsCommand(StringRef Name) const {
return Name == "returns" || Name == "return" || Name == "result";
}
const CommandInfo *registerUnknownCommand(StringRef CommandName);
inline unsigned CommandTraits::getBlockCommandNumArgs(StringRef Name) const {
return 0;
}
/// \returns a CommandInfo object for a given command name or
/// NULL if \c Name is not a builtin command.
static const CommandInfo *getBuiltinCommandInfo(StringRef Name);
inline bool CommandTraits::isInlineCommand(StringRef Name) const {
return llvm::StringSwitch<bool>(Name)
.Case("b", true)
.Cases("c", "p", true)
.Cases("a", "e", "em", true)
.Default(false);
}
/// \returns a CommandInfo object for a given command ID or
/// NULL if \c CommandID is not a builtin command.
static const CommandInfo *getBuiltinCommandInfo(unsigned CommandID);
private:
CommandTraits(const CommandTraits &) LLVM_DELETED_FUNCTION;
void operator=(const CommandTraits &) LLVM_DELETED_FUNCTION;
const CommandInfo *getRegisteredCommandInfo(StringRef Name) const;
const CommandInfo *getRegisteredCommandInfo(unsigned CommandID) const;
unsigned NextID;
/// Allocator for CommandInfo objects.
llvm::BumpPtrAllocator &Allocator;
SmallVector<CommandInfo *, 4> RegisteredCommands;
};
} // end namespace comments
} // end namespace clang

View File

@ -0,0 +1,156 @@
class Command<string name> {
string Name = name;
string EndCommandName = "";
int NumArgs = 0;
bit IsInlineCommand = 0;
bit IsBlockCommand = 0;
bit IsBriefCommand = 0;
bit IsReturnsCommand = 0;
bit IsParamCommand = 0;
bit IsTParamCommand = 0;
bit IsDeprecatedCommand = 0;
bit IsEmptyParagraphAllowed = 0;
bit IsVerbatimBlockCommand = 0;
bit IsVerbatimBlockEndCommand = 0;
bit IsVerbatimLineCommand = 0;
bit IsDeclarationCommand = 0;
}
class InlineCommand<string name> : Command<name> {
let IsInlineCommand = 1;
}
class BlockCommand<string name> : Command<name> {
let IsBlockCommand = 1;
}
class VerbatimBlockCommand<string name> : Command<name> {
let EndCommandName = name;
let IsVerbatimBlockCommand = 1;
}
multiclass VerbatimBlockCommand<string name, string endCommandName> {
def Begin : Command<name> {
let EndCommandName = endCommandName;
let IsVerbatimBlockCommand = 1;
}
def End : Command<endCommandName> {
let IsVerbatimBlockEndCommand = 1;
}
}
class VerbatimLineCommand<string name> : Command<name> {
let IsVerbatimLineCommand = 1;
}
class DeclarationVerbatimLineCommand<string name> :
VerbatimLineCommand<name> {
let IsDeclarationCommand = 1;
}
def B : InlineCommand<"b">;
def C : InlineCommand<"c">;
def P : InlineCommand<"p">;
def A : InlineCommand<"a">;
def E : InlineCommand<"e">;
def Em : InlineCommand<"em">;
def Brief : BlockCommand<"brief"> { let IsBriefCommand = 1; }
def Short : BlockCommand<"short"> { let IsBriefCommand = 1; }
def Returns : BlockCommand<"returns"> { let IsReturnsCommand = 1; }
def Return : BlockCommand<"return"> { let IsReturnsCommand = 1; }
def Result : BlockCommand<"result"> { let IsReturnsCommand = 1; }
def Param : BlockCommand<"param"> { let IsParamCommand = 1; }
// Doxygen
def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
// HeaderDoc
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
def Deprecated : BlockCommand<"deprecated"> {
let IsEmptyParagraphAllowed = 1;
let IsDeprecatedCommand = 1;
}
def Author : BlockCommand<"author">;
def Authors : BlockCommand<"authors">;
def Bug : BlockCommand<"bug">;
def Copyright : BlockCommand<"copyright">;
def Date : BlockCommand<"date">;
def Details : BlockCommand<"details">;
def Invariant : BlockCommand<"invariant">;
def Note : BlockCommand<"note">;
def Post : BlockCommand<"post">;
def Pre : BlockCommand<"pre">;
def Remark : BlockCommand<"remark">;
def Remarks : BlockCommand<"remarks">;
def Sa : BlockCommand<"sa">;
def See : BlockCommand<"see">;
def Since : BlockCommand<"since">;
def Todo : BlockCommand<"todo">;
def Version : BlockCommand<"version">;
def Warning : BlockCommand<"warning">;
defm Code : VerbatimBlockCommand<"code", "endcode">;
defm Verbatim : VerbatimBlockCommand<"verbatim", "endverbatim">;
defm Htmlonly : VerbatimBlockCommand<"htmlonly", "endhtmlonly">;
defm Latexonly : VerbatimBlockCommand<"latexonly", "endlatexonly">;
defm Xmlonly : VerbatimBlockCommand<"xmlonly", "endxmlonly">;
defm Manonly : VerbatimBlockCommand<"manonly", "endmanonly">;
defm Rtfonly : VerbatimBlockCommand<"rtfonly", "endrtfonly">;
defm Dot : VerbatimBlockCommand<"dot", "enddot">;
defm Msc : VerbatimBlockCommand<"msc", "endmsc">;
// These commands have special support in lexer.
def FDollar : VerbatimBlockCommand<"f$">; // Inline LaTeX formula
defm FBracket : VerbatimBlockCommand<"f[", "f]">; // Displayed LaTeX formula
defm FBrace : VerbatimBlockCommand<"f{", "f}">; // LaTeX environment
def Defgroup : VerbatimLineCommand<"defgroup">;
def Ingroup : VerbatimLineCommand<"ingroup">;
def Addtogroup : VerbatimLineCommand<"addtogroup">;
def Weakgroup : VerbatimLineCommand<"weakgroup">;
def Name : VerbatimLineCommand<"name">;
def Section : VerbatimLineCommand<"section">;
def Subsection : VerbatimLineCommand<"subsection">;
def Subsubsection : VerbatimLineCommand<"subsubsection">;
def Paragraph : VerbatimLineCommand<"paragraph">;
def Mainpage : VerbatimLineCommand<"mainpage">;
def Subpage : VerbatimLineCommand<"subpage">;
def Ref : VerbatimLineCommand<"ref">;
// Doxygen commands.
def Fn : DeclarationVerbatimLineCommand<"fn">;
def Namespace : DeclarationVerbatimLineCommand<"namespace">;
def Overload : DeclarationVerbatimLineCommand<"overload">;
def Property : DeclarationVerbatimLineCommand<"property">;
def Typedef : DeclarationVerbatimLineCommand<"typedef">;
def Var : DeclarationVerbatimLineCommand<"var">;
// HeaderDoc commands.
def Class : DeclarationVerbatimLineCommand<"class">;
def Interface : DeclarationVerbatimLineCommand<"interface">;
def Protocol : DeclarationVerbatimLineCommand<"protocol">;
def Category : DeclarationVerbatimLineCommand<"category">;
def Template : DeclarationVerbatimLineCommand<"template">;
def Function : DeclarationVerbatimLineCommand<"function">;
def Method : DeclarationVerbatimLineCommand<"method">;
def Callback : DeclarationVerbatimLineCommand<"callback">;
def Const : DeclarationVerbatimLineCommand<"const">;
def Constant : DeclarationVerbatimLineCommand<"constant">;
def Struct : DeclarationVerbatimLineCommand<"struct">;
def Union : DeclarationVerbatimLineCommand<"union">;
def Enum : DeclarationVerbatimLineCommand<"enum">;

View File

@ -0,0 +1,54 @@
class Tag<string spelling> {
string Spelling = spelling;
bit EndTagOptional = 0;
bit EndTagForbidden = 0;
}
def Em : Tag<"em">;
def Strong : Tag<"strong">;
def Tt : Tag<"tt">;
def I : Tag<"i">;
def B : Tag<"b">;
def Big : Tag<"big">;
def Small : Tag<"small">;
def Strike : Tag<"strike">;
def S : Tag<"s">;
def U : Tag<"u">;
def Font : Tag<"font">;
def A : Tag<"a">;
def Hr : Tag<"hr"> { let EndTagForbidden = 1; }
def Div : Tag<"div">;
def Span : Tag<"span">;
def H1 : Tag<"h1">;
def H2 : Tag<"h2">;
def H3 : Tag<"h3">;
def H4 : Tag<"h4">;
def H5 : Tag<"h5">;
def H6 : Tag<"h6">;
def Code : Tag<"code">;
def Blockquote : Tag<"blockquote">;
def Sub : Tag<"sub">;
def Sup : Tag<"sup">;
def Img : Tag<"img"> { let EndTagForbidden = 1; }
def P : Tag<"p"> { let EndTagOptional = 1; }
def Br : Tag<"br"> { let EndTagForbidden = 1; }
def Pre : Tag<"pre">;
def Ins : Tag<"ins">;
def Del : Tag<"del">;
def Ul : Tag<"ul">;
def Ol : Tag<"ol">;
def Li : Tag<"li"> { let EndTagOptional = 1; }
def Dl : Tag<"dl">;
def Dt : Tag<"dt"> { let EndTagOptional = 1; }
def Dd : Tag<"dd"> { let EndTagOptional = 1; }
def Table : Tag<"table">;
def Caption : Tag<"caption">;
def Thead : Tag<"thead"> { let EndTagOptional = 1; }
def Tfoot : Tag<"tfoot"> { let EndTagOptional = 1; }
def Tbody : Tag<"tbody"> { let EndTagOptional = 1; }
def Colgroup : Tag<"colgroup"> { let EndTagOptional = 1; }
def Col : Tag<"col"> { let EndTagForbidden = 1; }
def Tr : Tag<"tr"> { let EndTagOptional = 1; }
def Th : Tag<"th"> { let EndTagOptional = 1; }
def Td : Tag<"td"> { let EndTagOptional = 1; }

View File

@ -26,6 +26,7 @@ namespace comments {
class Lexer;
class TextTokenRetokenizer;
struct CommandInfo;
class CommandTraits;
namespace tok {
@ -33,7 +34,8 @@ enum TokenKind {
eof,
newline,
text,
command,
unknown_command, // Command that does not have an ID.
command, // Command with an ID.
verbatim_block_begin,
verbatim_block_line,
verbatim_block_end,
@ -49,11 +51,6 @@ enum TokenKind {
};
} // end namespace tok
class CommentOptions {
public:
bool Markdown;
};
/// \brief Comment token.
class Token {
friend class Lexer;
@ -70,8 +67,14 @@ class Token {
unsigned Length;
/// Contains text value associated with a token.
const char *TextPtr1;
unsigned TextLen1;
const char *TextPtr;
/// Integer value associated with a token.
///
/// If the token is a konwn command, contains command ID and TextPtr is
/// unused (command spelling can be found with CommandTraits). Otherwise,
/// contains the length of the string that starts at TextPtr.
unsigned IntVal;
public:
SourceLocation getLocation() const LLVM_READONLY { return Loc; }
@ -94,113 +97,120 @@ class Token {
StringRef getText() const LLVM_READONLY {
assert(is(tok::text));
return StringRef(TextPtr1, TextLen1);
return StringRef(TextPtr, IntVal);
}
void setText(StringRef Text) {
assert(is(tok::text));
TextPtr1 = Text.data();
TextLen1 = Text.size();
TextPtr = Text.data();
IntVal = Text.size();
}
StringRef getCommandName() const LLVM_READONLY {
StringRef getUnknownCommandName() const LLVM_READONLY {
assert(is(tok::unknown_command));
return StringRef(TextPtr, IntVal);
}
void setUnknownCommandName(StringRef Name) {
assert(is(tok::unknown_command));
TextPtr = Name.data();
IntVal = Name.size();
}
unsigned getCommandID() const LLVM_READONLY {
assert(is(tok::command));
return StringRef(TextPtr1, TextLen1);
return IntVal;
}
void setCommandName(StringRef Name) {
void setCommandID(unsigned ID) {
assert(is(tok::command));
TextPtr1 = Name.data();
TextLen1 = Name.size();
IntVal = ID;
}
StringRef getVerbatimBlockName() const LLVM_READONLY {
unsigned getVerbatimBlockID() const LLVM_READONLY {
assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
return StringRef(TextPtr1, TextLen1);
return IntVal;
}
void setVerbatimBlockName(StringRef Name) {
void setVerbatimBlockID(unsigned ID) {
assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
TextPtr1 = Name.data();
TextLen1 = Name.size();
IntVal = ID;
}
StringRef getVerbatimBlockText() const LLVM_READONLY {
assert(is(tok::verbatim_block_line));
return StringRef(TextPtr1, TextLen1);
return StringRef(TextPtr, IntVal);
}
void setVerbatimBlockText(StringRef Text) {
assert(is(tok::verbatim_block_line));
TextPtr1 = Text.data();
TextLen1 = Text.size();
TextPtr = Text.data();
IntVal = Text.size();
}
/// Returns the name of verbatim line command.
StringRef getVerbatimLineName() const LLVM_READONLY {
unsigned getVerbatimLineID() const LLVM_READONLY {
assert(is(tok::verbatim_line_name));
return StringRef(TextPtr1, TextLen1);
return IntVal;
}
void setVerbatimLineName(StringRef Name) {
void setVerbatimLineID(unsigned ID) {
assert(is(tok::verbatim_line_name));
TextPtr1 = Name.data();
TextLen1 = Name.size();
IntVal = ID;
}
StringRef getVerbatimLineText() const LLVM_READONLY {
assert(is(tok::verbatim_line_text));
return StringRef(TextPtr1, TextLen1);
return StringRef(TextPtr, IntVal);
}
void setVerbatimLineText(StringRef Text) {
assert(is(tok::verbatim_line_text));
TextPtr1 = Text.data();
TextLen1 = Text.size();
TextPtr = Text.data();
IntVal = Text.size();
}
StringRef getHTMLTagStartName() const LLVM_READONLY {
assert(is(tok::html_start_tag));
return StringRef(TextPtr1, TextLen1);
return StringRef(TextPtr, IntVal);
}
void setHTMLTagStartName(StringRef Name) {
assert(is(tok::html_start_tag));
TextPtr1 = Name.data();
TextLen1 = Name.size();
TextPtr = Name.data();
IntVal = Name.size();
}
StringRef getHTMLIdent() const LLVM_READONLY {
assert(is(tok::html_ident));
return StringRef(TextPtr1, TextLen1);
return StringRef(TextPtr, IntVal);
}
void setHTMLIdent(StringRef Name) {
assert(is(tok::html_ident));
TextPtr1 = Name.data();
TextLen1 = Name.size();
TextPtr = Name.data();
IntVal = Name.size();
}
StringRef getHTMLQuotedString() const LLVM_READONLY {
assert(is(tok::html_quoted_string));
return StringRef(TextPtr1, TextLen1);
return StringRef(TextPtr, IntVal);
}
void setHTMLQuotedString(StringRef Str) {
assert(is(tok::html_quoted_string));
TextPtr1 = Str.data();
TextLen1 = Str.size();
TextPtr = Str.data();
IntVal = Str.size();
}
StringRef getHTMLTagEndName() const LLVM_READONLY {
assert(is(tok::html_end_tag));
return StringRef(TextPtr1, TextLen1);
return StringRef(TextPtr, IntVal);
}
void setHTMLTagEndName(StringRef Name) {
assert(is(tok::html_end_tag));
TextPtr1 = Name.data();
TextLen1 = Name.size();
TextPtr = Name.data();
IntVal = Name.size();
}
void dump(const Lexer &L, const SourceManager &SM) const;
@ -209,8 +219,8 @@ class Token {
/// \brief Comment lexer.
class Lexer {
private:
Lexer(const Lexer&); // DO NOT IMPLEMENT
void operator=(const Lexer&); // DO NOT IMPLEMENT
Lexer(const Lexer &) LLVM_DELETED_FUNCTION;
void operator=(const Lexer &) LLVM_DELETED_FUNCTION;
/// Allocator for strings that are semantic values of tokens and have to be
/// computed (for example, resolved decimal character references).
@ -221,7 +231,6 @@ class Lexer {
const char *const BufferStart;
const char *const BufferEnd;
SourceLocation FileLoc;
CommentOptions CommOpts;
const char *BufferPtr;
@ -286,8 +295,8 @@ class Lexer {
Result.setKind(Kind);
Result.setLength(TokLen);
#ifndef NDEBUG
Result.TextPtr1 = "<UNSET>";
Result.TextLen1 = 7;
Result.TextPtr = "<UNSET>";
Result.IntVal = 7;
#endif
BufferPtr = TokEnd;
}
@ -314,13 +323,14 @@ class Lexer {
void setupAndLexVerbatimBlock(Token &T,
const char *TextBegin,
char Marker, StringRef EndName);
char Marker, const CommandInfo *Info);
void lexVerbatimBlockFirstLine(Token &T);
void lexVerbatimBlockBody(Token &T);
void setupAndLexVerbatimLine(Token &T, const char *TextBegin);
void setupAndLexVerbatimLine(Token &T, const char *TextBegin,
const CommandInfo *Info);
void lexVerbatimLineText(Token &T);
@ -336,7 +346,7 @@ class Lexer {
public:
Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits,
SourceLocation FileLoc, const CommentOptions &CommOpts,
SourceLocation FileLoc,
const char *BufferStart, const char *BufferEnd);
void lex(Token &T);

View File

@ -28,8 +28,8 @@ class CommandTraits;
/// Doxygen comment parser.
class Parser {
Parser(const Parser&); // DO NOT IMPLEMENT
void operator=(const Parser&); // DO NOT IMPLEMENT
Parser(const Parser &) LLVM_DELETED_FUNCTION;
void operator=(const Parser &) LLVM_DELETED_FUNCTION;
friend class TextTokenRetokenizer;

View File

@ -25,13 +25,14 @@
namespace clang {
class Decl;
class SourceMgr;
class Preprocessor;
namespace comments {
class CommandTraits;
class Sema {
Sema(const Sema&); // DO NOT IMPLEMENT
void operator=(const Sema&); // DO NOT IMPLEMENT
Sema(const Sema &) LLVM_DELETED_FUNCTION;
void operator=(const Sema &) LLVM_DELETED_FUNCTION;
/// Allocator for AST nodes.
llvm::BumpPtrAllocator &Allocator;
@ -41,18 +42,13 @@ class Sema {
DiagnosticsEngine &Diags;
const CommandTraits &Traits;
CommandTraits &Traits;
const Preprocessor *PP;
/// Information about the declaration this comment is attached to.
DeclInfo *ThisDeclInfo;
/// Comment AST nodes that correspond to \c ParamVars for which we have
/// found a \\param command or NULL if no documentation was found so far.
///
/// Has correct size and contains valid values if \c DeclInfo->IsFilled is
/// true.
llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
/// Comment AST nodes that correspond to parameter names in
/// \c TemplateParameters.
///
@ -75,7 +71,8 @@ class Sema {
public:
Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
DiagnosticsEngine &Diags, const CommandTraits &Traits);
DiagnosticsEngine &Diags, CommandTraits &Traits,
const Preprocessor *PP);
void setDecl(const Decl *D);
@ -96,7 +93,7 @@ class Sema {
BlockCommandComment *actOnBlockCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name);
unsigned CommandID);
void actOnBlockCommandArgs(BlockCommandComment *Command,
ArrayRef<BlockCommandComment::Argument> Args);
@ -106,7 +103,7 @@ class Sema {
ParamCommandComment *actOnParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name);
unsigned CommandID);
void actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
@ -123,7 +120,7 @@ class Sema {
TParamCommandComment *actOnTParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name);
unsigned CommandID);
void actOnTParamCommandParamNameArg(TParamCommandComment *Command,
SourceLocation ArgLocBegin,
@ -135,25 +132,29 @@ class Sema {
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
StringRef CommandName);
unsigned CommandID);
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
StringRef CommandName,
unsigned CommandID,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
StringRef Arg);
InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name);
StringRef CommandName);
InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
SourceLocation LocEnd,
unsigned CommandID);
TextComment *actOnText(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Text);
VerbatimBlockComment *actOnVerbatimBlockStart(SourceLocation Loc,
StringRef Name);
unsigned CommandID);
VerbatimBlockLineComment *actOnVerbatimBlockLine(SourceLocation Loc,
StringRef Text);
@ -164,7 +165,7 @@ class Sema {
ArrayRef<VerbatimBlockLineComment *> Lines);
VerbatimLineComment *actOnVerbatimLine(SourceLocation LocBegin,
StringRef Name,
unsigned CommandID,
SourceLocation TextBegin,
StringRef Text);
@ -190,6 +191,12 @@ class Sema {
/// used only once per comment, e.g., \\brief and \\returns.
void checkBlockCommandDuplicate(const BlockCommandComment *Command);
void checkDeprecatedCommand(const BlockCommandComment *Comment);
/// Resolve parameter names to parameter indexes in function declaration.
/// Emit diagnostics about unknown parametrs.
void resolveParamCommandIndexes(const FullComment *FC);
bool isFunctionDecl();
bool isTemplateOrSpecialization();
@ -218,9 +225,6 @@ class Sema {
InlineCommandComment::RenderKind
getInlineCommandRenderKind(StringRef Name) const;
bool isHTMLEndTagOptional(StringRef Name);
bool isHTMLEndTagForbidden(StringRef Name);
};
} // end namespace comments

View File

@ -88,7 +88,6 @@ class TranslationUnitDecl : public Decl, public DeclContext {
static TranslationUnitDecl *Create(ASTContext &C);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TranslationUnitDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TranslationUnit; }
static DeclContext *castToDeclContext(const TranslationUnitDecl *D) {
return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D));
@ -214,16 +213,19 @@ class NamedDecl : public Decl {
bool isCXXInstanceMember() const;
class LinkageInfo {
Linkage linkage_;
Visibility visibility_;
bool explicit_;
uint8_t linkage_ : 2;
uint8_t visibility_ : 2;
uint8_t explicit_ : 1;
void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
public:
LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility),
explicit_(false) {}
LinkageInfo(Linkage L, Visibility V, bool E)
: linkage_(L), visibility_(V), explicit_(E) {}
: linkage_(L), visibility_(V), explicit_(E) {
assert(linkage() == L && visibility() == V && visibilityExplicit() == E &&
"Enum truncated!");
}
static LinkageInfo external() {
return LinkageInfo();
@ -238,8 +240,8 @@ class NamedDecl : public Decl {
return LinkageInfo(NoLinkage, DefaultVisibility, false);
}
Linkage linkage() const { return linkage_; }
Visibility visibility() const { return visibility_; }
Linkage linkage() const { return (Linkage)linkage_; }
Visibility visibility() const { return (Visibility)visibility_; }
bool visibilityExplicit() const { return explicit_; }
void setLinkage(Linkage L) { linkage_ = L; }
@ -337,7 +339,6 @@ class NamedDecl : public Decl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NamedDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
};
@ -383,7 +384,6 @@ class LabelDecl : public NamedDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const LabelDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Label; }
};
@ -509,7 +509,6 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NamespaceDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Namespace; }
static DeclContext *castToDeclContext(const NamespaceDecl *D) {
return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D));
@ -545,7 +544,6 @@ class ValueDecl : public NamedDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ValueDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; }
};
@ -578,8 +576,8 @@ struct QualifierInfo {
private:
// Copy constructor and copy assignment are disabled.
QualifierInfo(const QualifierInfo&);
QualifierInfo& operator=(const QualifierInfo&);
QualifierInfo(const QualifierInfo&) LLVM_DELETED_FUNCTION;
QualifierInfo& operator=(const QualifierInfo&) LLVM_DELETED_FUNCTION;
};
/// \brief Represents a ValueDecl that came out of a declarator.
@ -666,7 +664,6 @@ class DeclaratorDecl : public ValueDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const DeclaratorDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstDeclarator && K <= lastDeclarator;
}
@ -712,7 +709,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
typedef clang::StorageClass StorageClass;
/// getStorageClassSpecifierString - Return the string used to
/// specify the storage class \arg SC.
/// specify the storage class \p SC.
///
/// It is illegal to call this function with SC == None.
static const char *getStorageClassSpecifierString(StorageClass SC);
@ -1208,7 +1205,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const VarDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; }
};
@ -1229,7 +1225,6 @@ class ImplicitParamDecl : public VarDecl {
}
// Implement isa/cast/dyncast/etc.
static bool classof(const ImplicitParamDecl *D) { return true; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ImplicitParam; }
};
@ -1399,7 +1394,6 @@ class ParmVarDecl : public VarDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ParmVarDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ParmVar; }
private:
@ -2070,7 +2064,6 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FunctionDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstFunction && K <= lastFunction;
}
@ -2204,7 +2197,6 @@ class FieldDecl : public DeclaratorDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FieldDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstField && K <= lastField; }
friend class ASTDeclReader;
@ -2243,7 +2235,6 @@ class EnumConstantDecl : public ValueDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const EnumConstantDecl *D) { return true; }
static bool classofKind(Kind K) { return K == EnumConstant; }
friend class StmtIteratorBase;
@ -2287,7 +2278,6 @@ class IndirectFieldDecl : public ValueDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const IndirectFieldDecl *D) { return true; }
static bool classofKind(Kind K) { return K == IndirectField; }
friend class ASTDeclReader;
};
@ -2334,7 +2324,6 @@ class TypeDecl : public NamedDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TypeDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstType && K <= lastType; }
};
@ -2390,7 +2379,6 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TypedefNameDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstTypedefName && K <= lastTypedefName;
}
@ -2413,7 +2401,6 @@ class TypedefDecl : public TypedefNameDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TypedefDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Typedef; }
};
@ -2434,7 +2421,6 @@ class TypeAliasDecl : public TypedefNameDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TypeAliasDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TypeAlias; }
};
@ -2448,7 +2434,7 @@ class TagDecl
private:
// FIXME: This can be packed into the bitfields in Decl.
/// TagDeclKind - The TagKind enum.
unsigned TagDeclKind : 2;
unsigned TagDeclKind : 3;
/// IsCompleteDefinition - True if this is a definition ("struct foo
/// {};"), false if it is a declaration ("struct foo;"). It is not
@ -2625,6 +2611,7 @@ class TagDecl
void setTagKind(TagKind TK) { TagDeclKind = TK; }
bool isStruct() const { return getTagKind() == TTK_Struct; }
bool isInterface() const { return getTagKind() == TTK_Interface; }
bool isClass() const { return getTagKind() == TTK_Class; }
bool isUnion() const { return getTagKind() == TTK_Union; }
bool isEnum() const { return getTagKind() == TTK_Enum; }
@ -2665,7 +2652,6 @@ class TagDecl
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TagDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstTag && K <= lastTag; }
static DeclContext *castToDeclContext(const TagDecl *D) {
@ -2895,7 +2881,6 @@ class EnumDecl : public TagDecl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const EnumDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Enum; }
friend class ASTDeclReader;
@ -3026,11 +3011,15 @@ class RecordDecl : public TagDecl {
virtual void completeDefinition();
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const RecordDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstRecord && K <= lastRecord;
}
/// isMsStrust - Get whether or not this is an ms_struct which can
/// be turned on with an attribute, pragma, or -mms-bitfields
/// commandline option.
bool isMsStruct(const ASTContext &C) const;
private:
/// \brief Deserialize just the fields.
void LoadFieldsFromExternalStorage() const;
@ -3062,7 +3051,6 @@ class FileScopeAsmDecl : public Decl {
void setAsmString(StringLiteral *Asm) { AsmString = Asm; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FileScopeAsmDecl *D) { return true; }
static bool classofKind(Kind K) { return K == FileScopeAsm; }
};
@ -3208,7 +3196,6 @@ class BlockDecl : public Decl, public DeclContext {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const BlockDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Block; }
static DeclContext *castToDeclContext(const BlockDecl *D) {
return static_cast<DeclContext *>(const_cast<BlockDecl*>(D));
@ -3282,7 +3269,6 @@ class ImportDecl : public Decl {
virtual SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ImportDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Import; }
};

View File

@ -430,16 +430,10 @@ class Decl {
void dropAttr() {
if (!HasAttrs) return;
AttrVec &Attrs = getAttrs();
for (unsigned i = 0, e = Attrs.size(); i != e; /* in loop */) {
if (isa<T>(Attrs[i])) {
Attrs.erase(Attrs.begin() + i);
--e;
}
else
++i;
}
if (Attrs.empty())
AttrVec &Vec = getAttrs();
Vec.erase(std::remove_if(Vec.begin(), Vec.end(), isa<T, Attr*>), Vec.end());
if (Vec.empty())
HasAttrs = false;
}
@ -844,8 +838,6 @@ class Decl {
IdentifierNamespace |= IDNS_NonMemberOperator;
}
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *) { return true; }
static bool classofKind(Kind K) { return true; }
static DeclContext *castToDeclContext(const Decl *);
static Decl *castFromDeclContext(const DeclContext *);
@ -1479,6 +1471,13 @@ class DeclContext {
inline ddiag_iterator ddiag_end() const;
// Low-level accessors
/// \brief Mark the lookup table as needing to be built. This should be
/// used only if setHasExternalLexicalStorage() has been called.
void setMustBuildLookupTable() {
assert(ExternalLexicalStorage && "Requires external lexical storage");
LookupPtr.setInt(true);
}
/// \brief Retrieve the internal representation of the lookup structure.
/// This may omit some names if we are lazily building the structure.
@ -1516,10 +1515,6 @@ class DeclContext {
static bool classof(const Decl *D);
static bool classof(const DeclContext *D) { return true; }
#define DECL(NAME, BASE)
#define DECL_CONTEXT(NAME) \
static bool classof(const NAME##Decl *D) { return true; }
#include "clang/AST/DeclNodes.inc"
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;

View File

@ -145,7 +145,6 @@ class AccessSpecDecl : public Decl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const AccessSpecDecl *D) { return true; }
static bool classofKind(Kind K) { return K == AccessSpec; }
};
@ -563,9 +562,10 @@ class CXXRecordDecl : public RecordDecl {
struct LambdaDefinitionData : public DefinitionData {
typedef LambdaExpr::Capture Capture;
LambdaDefinitionData(CXXRecordDecl *D, bool Dependent)
LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent)
: DefinitionData(D), Dependent(Dependent), NumCaptures(0),
NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0)
NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0),
MethodTyInfo(Info)
{
IsLambda = true;
}
@ -598,7 +598,10 @@ class CXXRecordDecl : public RecordDecl {
/// \brief The list of captures, both explicit and implicit, for this
/// lambda.
Capture *Captures;
Capture *Captures;
/// \brief The type of the call method.
TypeSourceInfo *MethodTyInfo;
};
struct DefinitionData &data() {
@ -705,7 +708,8 @@ class CXXRecordDecl : public RecordDecl {
IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0,
bool DelayTypeCreation = false);
static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
SourceLocation Loc, bool DependentLambda);
TypeSourceInfo *Info, SourceLocation Loc,
bool DependentLambda);
static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
bool isDynamicClass() const {
@ -1303,7 +1307,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief Function type used by forallBases() as a callback.
///
/// \param Base the definition of the base class
/// \param BaseDefinition the definition of the base class
///
/// \returns true if this base matched the search criteria
typedef bool ForallBasesCallback(const CXXRecordDecl *BaseDefinition,
@ -1500,15 +1504,15 @@ class CXXRecordDecl : public RecordDecl {
bool isDependentLambda() const {
return isLambda() && getLambdaData().Dependent;
}
TypeSourceInfo *getLambdaTypeInfo() const {
return getLambdaData().MethodTyInfo;
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstCXXRecord && K <= lastCXXRecord;
}
static bool classof(const CXXRecordDecl *D) { return true; }
static bool classof(const ClassTemplateSpecializationDecl *D) {
return true;
}
friend class ASTDeclReader;
friend class ASTDeclWriter;
@ -1549,14 +1553,16 @@ class CXXMethodDecl : public FunctionDecl {
bool isStatic() const { return getStorageClass() == SC_Static; }
bool isInstance() const { return !isStatic(); }
bool isConst() { return getType()->castAs<FunctionType>()->isConst(); }
bool isVolatile() { return getType()->castAs<FunctionType>()->isVolatile(); }
bool isConst() const { return getType()->castAs<FunctionType>()->isConst(); }
bool isVolatile() const { return getType()->castAs<FunctionType>()->isVolatile(); }
bool isVirtual() const {
CXXMethodDecl *CD =
cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl());
if (CD->isVirtualAsWritten())
// Methods declared in interfaces are automatically (pure) virtual.
if (CD->isVirtualAsWritten() ||
(CD->getParent()->isInterface() && CD->isUserProvided()))
return true;
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
@ -1661,7 +1667,6 @@ class CXXMethodDecl : public FunctionDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXMethodDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstCXXMethod && K <= lastCXXMethod;
}
@ -2141,7 +2146,6 @@ class CXXConstructorDecl : public CXXMethodDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXConstructorDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CXXConstructor; }
friend class ASTDeclReader;
@ -2213,7 +2217,6 @@ class CXXDestructorDecl : public CXXMethodDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXDestructorDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CXXDestructor; }
friend class ASTDeclReader;
@ -2280,7 +2283,6 @@ class CXXConversionDecl : public CXXMethodDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXConversionDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CXXConversion; }
friend class ASTDeclReader;
@ -2350,7 +2352,6 @@ class LinkageSpecDecl : public Decl, public DeclContext {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const LinkageSpecDecl *D) { return true; }
static bool classofKind(Kind K) { return K == LinkageSpec; }
static DeclContext *castToDeclContext(const LinkageSpecDecl *D) {
return static_cast<DeclContext *>(const_cast<LinkageSpecDecl*>(D));
@ -2454,7 +2455,6 @@ class UsingDirectiveDecl : public NamedDecl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UsingDirectiveDecl *D) { return true; }
static bool classofKind(Kind K) { return K == UsingDirective; }
// Friend for getUsingDirectiveName.
@ -2548,7 +2548,6 @@ class NamespaceAliasDecl : public NamedDecl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NamespaceAliasDecl *D) { return true; }
static bool classofKind(Kind K) { return K == NamespaceAlias; }
};
@ -2619,7 +2618,6 @@ class UsingShadowDecl : public NamedDecl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UsingShadowDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Decl::UsingShadow; }
friend class ASTDeclReader;
@ -2751,7 +2749,6 @@ class UsingDecl : public NamedDecl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UsingDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Using; }
friend class ASTDeclReader;
@ -2825,7 +2822,6 @@ class UnresolvedUsingValueDecl : public ValueDecl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UnresolvedUsingValueDecl *D) { return true; }
static bool classofKind(Kind K) { return K == UnresolvedUsingValue; }
friend class ASTDeclReader;
@ -2891,7 +2887,6 @@ class UnresolvedUsingTypenameDecl : public TypeDecl {
CreateDeserialized(ASTContext &C, unsigned ID);
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UnresolvedUsingTypenameDecl *D) { return true; }
static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; }
};
@ -2931,7 +2926,6 @@ class StaticAssertDecl : public Decl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(StaticAssertDecl *D) { return true; }
static bool classofKind(Kind K) { return K == StaticAssert; }
friend class ASTDeclReader;

View File

@ -16,6 +16,7 @@
#define LLVM_CLANG_AST_DECLFRIEND_H
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "llvm/Support/Compiler.h"
namespace clang {
@ -104,9 +105,15 @@ class FriendDecl : public Decl {
/// Retrieves the source range for the friend declaration.
SourceRange getSourceRange() const LLVM_READONLY {
/* FIXME: consider the case of templates wrt start of range. */
if (NamedDecl *ND = getFriendDecl())
if (NamedDecl *ND = getFriendDecl()) {
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
return FTD->getSourceRange();
if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(ND)) {
if (DD->getOuterLocStart() != DD->getInnerLocStart())
return DD->getSourceRange();
}
return SourceRange(getFriendLoc(), ND->getLocEnd());
}
else if (TypeSourceInfo *TInfo = getFriendType())
return SourceRange(getFriendLoc(), TInfo->getTypeLoc().getEndLoc());
else
@ -123,7 +130,6 @@ class FriendDecl : public Decl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FriendDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Decl::Friend; }
friend class ASTDeclReader;

View File

@ -33,8 +33,8 @@ class ObjCPropertyImplDecl;
class CXXCtorInitializer;
class ObjCListBase {
void operator=(const ObjCListBase &); // DO NOT IMPLEMENT
ObjCListBase(const ObjCListBase&); // DO NOT IMPLEMENT
ObjCListBase(const ObjCListBase &) LLVM_DELETED_FUNCTION;
void operator=(const ObjCListBase &) LLVM_DELETED_FUNCTION;
protected:
/// List is an array of pointers to objects that are not owned by this object.
void **List;
@ -123,8 +123,8 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
unsigned IsInstance : 1;
unsigned IsVariadic : 1;
// Synthesized declaration method for a property setter/getter
unsigned IsSynthesized : 1;
/// True if this method is the getter or setter for an explicit property.
unsigned IsPropertyAccessor : 1;
// Method has a definition.
unsigned IsDefined : 1;
@ -174,8 +174,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
SourceLocation DeclEndLoc; // the location of the ';' or '{'.
// The following are only used for method definitions, null otherwise.
// FIXME: space savings opportunity, consider a sub-class.
Stmt *Body;
LazyDeclStmtPtr Body;
/// SelfDecl - Decl for the implicit self parameter. This is lazily
/// constructed by createImplicitParams.
@ -227,7 +226,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
DeclContext *contextDecl,
bool isInstance = true,
bool isVariadic = false,
bool isSynthesized = false,
bool isPropertyAccessor = false,
bool isImplicitlyDeclared = false,
bool isDefined = false,
ImplementationControl impControl = None,
@ -235,14 +234,14 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily),
IsInstance(isInstance), IsVariadic(isVariadic),
IsSynthesized(isSynthesized),
IsPropertyAccessor(isPropertyAccessor),
IsDefined(isDefined), IsRedeclaration(0), HasRedeclaration(0),
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
RelatedResultType(HasRelatedResultType),
SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0),
MethodDeclType(T), ResultTInfo(ResultTInfo),
ParamsAndSelLocs(0), NumParams(0),
DeclEndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {
DeclEndLoc(endLoc), Body(), SelfDecl(0), CmdDecl(0) {
setImplicit(isImplicitlyDeclared);
}
@ -261,7 +260,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
DeclContext *contextDecl,
bool isInstance = true,
bool isVariadic = false,
bool isSynthesized = false,
bool isPropertyAccessor = false,
bool isImplicitlyDeclared = false,
bool isDefined = false,
ImplementationControl impControl = None,
@ -363,7 +362,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
}
/// \brief Sets the method's parameters and selector source locations.
/// If the method is implicit (not coming from source) \arg SelLocs is
/// If the method is implicit (not coming from source) \p SelLocs is
/// ignored.
void setMethodParams(ASTContext &C,
ArrayRef<ParmVarDecl*> Params,
@ -403,8 +402,8 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
bool isClassMethod() const { return !IsInstance; }
bool isSynthesized() const { return IsSynthesized; }
void setSynthesized(bool isSynth) { IsSynthesized = isSynth; }
bool isPropertyAccessor() const { return IsPropertyAccessor; }
void setPropertyAccessor(bool isAccessor) { IsPropertyAccessor = isAccessor; }
bool isDefined() const { return IsDefined; }
void setDefined(bool isDefined) { IsDefined = isDefined; }
@ -418,7 +417,25 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
/// method in the interface or its categories.
bool isOverriding() const { return IsOverriding; }
void setOverriding(bool isOverriding) { IsOverriding = isOverriding; }
/// \brief Return overridden methods for the given \p Method.
///
/// An ObjC method is considered to override any method in the class's
/// base classes (and base's categories), its protocols, or its categories'
/// protocols, that has
/// the same selector and is of the same kind (class or instance).
/// A method in an implementation is not considered as overriding the same
/// method in the interface or its categories.
void getOverriddenMethods(
SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const;
/// \brief Returns the property associated with this method's selector.
///
/// Note that even if this particular method is not marked as a property
/// accessor, it is still possible for it to match a property declared in a
/// superclass. Pass \c false if you only want to check the current class.
const ObjCPropertyDecl *findPropertyDecl(bool CheckOverrides = true) const;
// Related to protocols declared in \@protocol
void setDeclImplementation(ImplementationControl ic) {
DeclImplementation = ic;
@ -427,10 +444,15 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
return ImplementationControl(DeclImplementation);
}
virtual Stmt *getBody() const {
return (Stmt*) Body;
}
CompoundStmt *getCompoundBody() { return (CompoundStmt*)Body; }
/// \brief Determine whether this method has a body.
virtual bool hasBody() const { return Body; }
/// \brief Retrieve the body of this method, if it has one.
virtual Stmt *getBody() const;
void setLazyBody(uint64_t Offset) { Body = Offset; }
CompoundStmt *getCompoundBody() { return (CompoundStmt*)getBody(); }
void setBody(Stmt *B) { Body = B; }
/// \brief Returns whether this specific method is a definition.
@ -438,7 +460,6 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCMethodDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCMethod; }
static DeclContext *castToDeclContext(const ObjCMethodDecl *D) {
return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D));
@ -520,6 +541,13 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const;
typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
/// This routine collects list of properties to be implemented in the class.
/// This includes, class's and its conforming protocols' properties.
/// Note, the superclass's properties are not included in the list.
virtual void collectPropertiesToImplement(PropertyMap &PM) const {}
SourceLocation getAtStartLoc() const { return AtStart; }
void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; }
@ -537,7 +565,6 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCContainerDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstObjCContainer &&
K <= lastObjCContainer;
@ -880,6 +907,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
ObjCPropertyDecl
*FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const;
virtual void collectPropertiesToImplement(PropertyMap &PM) const;
/// isSuperClassOf - Return true if this class is the specified class or is a
/// super class of the specified interface class.
bool isSuperClassOf(const ObjCInterfaceDecl *I) const {
@ -992,7 +1021,6 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCInterfaceDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCInterface; }
friend class ASTReader;
@ -1065,7 +1093,6 @@ class ObjCIvarDecl : public FieldDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCIvarDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCIvar; }
private:
/// NextIvar - Next Ivar in the list of ivars declared in class; class's
@ -1098,7 +1125,6 @@ class ObjCAtDefsFieldDecl : public FieldDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCAtDefsFieldDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCAtDefsField; }
};
@ -1277,8 +1303,9 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
return getFirstDeclaration();
}
virtual void collectPropertiesToImplement(PropertyMap &PM) const;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCProtocolDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCProtocol; }
friend class ASTReader;
@ -1402,7 +1429,6 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCCategoryDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCCategory; }
friend class ASTDeclReader;
@ -1455,7 +1481,6 @@ class ObjCImplDecl : public ObjCContainerDecl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCImplDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstObjCImpl && K <= lastObjCImpl;
}
@ -1532,7 +1557,6 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCCategoryImplDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
friend class ASTDeclReader;
@ -1568,8 +1592,12 @@ class ObjCImplementationDecl : public ObjCImplDecl {
CXXCtorInitializer **IvarInitializers;
unsigned NumIvarInitializers;
/// true if class has a .cxx_[construct,destruct] method.
bool HasCXXStructors : 1;
/// Do the ivars of this class require initialization other than
/// zero-initialization?
bool HasNonZeroConstructors : 1;
/// Do the ivars of this class require non-trivial destruction?
bool HasDestructors : 1;
ObjCImplementationDecl(DeclContext *DC,
ObjCInterfaceDecl *classInterface,
@ -1581,7 +1609,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc),
IvarRBraceLoc(IvarRBraceLoc),
IvarInitializers(0), NumIvarInitializers(0),
HasCXXStructors(false) {}
HasNonZeroConstructors(false), HasDestructors(false) {}
public:
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
ObjCInterfaceDecl *classInterface,
@ -1625,8 +1653,15 @@ class ObjCImplementationDecl : public ObjCImplDecl {
CXXCtorInitializer ** initializers,
unsigned numInitializers);
bool hasCXXStructors() const { return HasCXXStructors; }
void setHasCXXStructors(bool val) { HasCXXStructors = val; }
/// Do any of the ivars of this class (not counting its base classes)
/// require construction other than zero-initialization?
bool hasNonZeroConstructors() const { return HasNonZeroConstructors; }
void setHasNonZeroConstructors(bool val) { HasNonZeroConstructors = val; }
/// Do any of the ivars of this class (not counting its base classes)
/// require non-trivial destruction?
bool hasDestructors() const { return HasDestructors; }
void setHasDestructors(bool val) { HasDestructors = val; }
/// getIdentifier - Get the identifier that names the class
/// interface associated with this implementation.
@ -1676,7 +1711,6 @@ class ObjCImplementationDecl : public ObjCImplDecl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCImplementationDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCImplementation; }
friend class ASTDeclReader;
@ -1708,7 +1742,6 @@ class ObjCCompatibleAliasDecl : public NamedDecl {
void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCCompatibleAliasDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCCompatibleAlias; }
};
@ -1882,13 +1915,15 @@ class ObjCPropertyDecl : public NamedDecl {
virtual SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtLoc, getLocation());
}
/// Get the default name of the synthesized ivar.
IdentifierInfo *getDefaultSynthIvarName(ASTContext &Ctx) const;
/// Lookup a property by name in the specified DeclContext.
static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC,
IdentifierInfo *propertyID);
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCPropertyDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCProperty; }
};
@ -1999,7 +2034,6 @@ class ObjCPropertyImplDecl : public Decl {
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCPropertyImplDecl *D) { return true; }
static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; }
friend class ASTDeclReader;

View File

@ -50,7 +50,11 @@ class TemplateParameterList {
/// The number of template parameters in this template
/// parameter list.
unsigned NumParams;
unsigned NumParams : 31;
/// Whether this template parameter list contains an unexpanded parameter
/// pack.
unsigned ContainsUnexpandedParameterPack : 1;
protected:
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
@ -104,6 +108,12 @@ class TemplateParameterList {
/// the second template parameter list will have depth 1, etc.
unsigned getDepth() const;
/// \brief Determine whether this template parameter list contains an
/// unexpanded parameter pack.
bool containsUnexpandedParameterPack() const {
return ContainsUnexpandedParameterPack;
}
SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; }
SourceLocation getRAngleLoc() const { return RAngleLoc; }
@ -139,8 +149,8 @@ class TemplateArgumentList {
/// argument list.
unsigned NumArguments;
TemplateArgumentList(const TemplateArgumentList &Other); // DO NOT IMPL
void operator=(const TemplateArgumentList &Other); // DO NOT IMPL
TemplateArgumentList(const TemplateArgumentList &Other) LLVM_DELETED_FUNCTION;
void operator=(const TemplateArgumentList &Other) LLVM_DELETED_FUNCTION;
TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs,
bool Owned)
@ -233,12 +243,6 @@ class TemplateDecl : public NamedDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TemplateDecl *D) { return true; }
static bool classof(const RedeclarableTemplateDecl *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; }
static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstTemplate && K <= lastTemplate;
}
@ -678,10 +682,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const RedeclarableTemplateDecl *D) { return true; }
static bool classof(const FunctionTemplateDecl *D) { return true; }
static bool classof(const ClassTemplateDecl *D) { return true; }
static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate;
}
@ -827,7 +827,6 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FunctionTemplateDecl *D) { return true; }
static bool classofKind(Kind K) { return K == FunctionTemplate; }
friend class ASTDeclReader;
@ -969,7 +968,6 @@ class TemplateTypeParmDecl : public TypeDecl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TemplateTypeParmDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TemplateTypeParm; }
};
@ -1090,8 +1088,17 @@ class NonTypeTemplateParmDecl
/// \endcode
bool isParameterPack() const { return ParameterPack; }
/// \brief Whether this parameter pack is a pack expansion.
///
/// A non-type template parameter pack is a pack expansion if its type
/// contains an unexpanded parameter pack. In this case, we will have
/// built a PackExpansionType wrapping the type.
bool isPackExpansion() const {
return ParameterPack && getType()->getAs<PackExpansionType>();
}
/// \brief Whether this parameter is a non-type template parameter pack
/// that has different types at different positions.
/// that has a known list of different types at different positions.
///
/// A parameter pack is an expanded parameter pack when the original
/// parameter pack's type was itself a pack expansion, and that expansion
@ -1141,7 +1148,6 @@ class NonTypeTemplateParmDecl
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
static bool classofKind(Kind K) { return K == NonTypeTemplateParm; }
};
@ -1165,23 +1171,47 @@ class TemplateTemplateParmDecl : public TemplateDecl,
/// \brief Whether this parameter is a parameter pack.
bool ParameterPack;
/// \brief Whether this template template parameter is an "expanded"
/// parameter pack, meaning that it is a pack expansion and we
/// already know the set of template parameters that expansion expands to.
bool ExpandedParameterPack;
/// \brief The number of parameters in an expanded parameter pack.
unsigned NumExpandedParams;
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P, bool ParameterPack,
IdentifierInfo *Id, TemplateParameterList *Params)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
TemplateParmPosition(D, P), DefaultArgument(),
DefaultArgumentWasInherited(false), ParameterPack(ParameterPack)
DefaultArgumentWasInherited(false), ParameterPack(ParameterPack),
ExpandedParameterPack(false), NumExpandedParams(0)
{ }
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P,
IdentifierInfo *Id, TemplateParameterList *Params,
unsigned NumExpansions,
TemplateParameterList * const *Expansions);
public:
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
unsigned P, bool ParameterPack,
IdentifierInfo *Id,
TemplateParameterList *Params);
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
unsigned P,
IdentifierInfo *Id,
TemplateParameterList *Params,
llvm::ArrayRef<TemplateParameterList*> Expansions);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned NumExpansions);
using TemplateParmPosition::getDepth;
using TemplateParmPosition::getPosition;
@ -1195,6 +1225,49 @@ class TemplateTemplateParmDecl : public TemplateDecl,
/// \endcode
bool isParameterPack() const { return ParameterPack; }
/// \brief Whether this parameter pack is a pack expansion.
///
/// A template template parameter pack is a pack expansion if its template
/// parameter list contains an unexpanded parameter pack.
bool isPackExpansion() const {
return ParameterPack &&
getTemplateParameters()->containsUnexpandedParameterPack();
}
/// \brief Whether this parameter is a template template parameter pack that
/// has a known list of different template parameter lists at different
/// positions.
///
/// A parameter pack is an expanded parameter pack when the original parameter
/// pack's template parameter list was itself a pack expansion, and that
/// expansion has already been expanded. For exampe, given:
///
/// \code
/// template<typename...Types> struct Outer {
/// template<template<Types> class...Templates> struct Inner;
/// };
/// \endcode
///
/// The parameter pack \c Templates is a pack expansion, which expands the
/// pack \c Types. When \c Types is supplied with template arguments by
/// instantiating \c Outer, the instantiation of \c Templates is an expanded
/// parameter pack.
bool isExpandedParameterPack() const { return ExpandedParameterPack; }
/// \brief Retrieves the number of expansion template parameters in
/// an expanded parameter pack.
unsigned getNumExpansionTemplateParameters() const {
assert(ExpandedParameterPack && "Not an expansion parameter pack");
return NumExpandedParams;
}
/// \brief Retrieve a particular expansion type within an expanded parameter
/// pack.
TemplateParameterList *getExpansionTemplateParameters(unsigned I) const {
assert(I < NumExpandedParams && "Out-of-range expansion type index");
return reinterpret_cast<TemplateParameterList *const *>(this + 1)[I];
}
/// \brief Determine whether this template parameter has a default
/// argument.
bool hasDefaultArgument() const {
@ -1238,7 +1311,6 @@ class TemplateTemplateParmDecl : public TemplateDecl,
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TemplateTemplateParm; }
friend class ASTDeclReader;
@ -1505,14 +1577,6 @@ class ClassTemplateSpecializationDecl
K <= lastClassTemplateSpecialization;
}
static bool classof(const ClassTemplateSpecializationDecl *) {
return true;
}
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
return true;
}
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
@ -1681,10 +1745,6 @@ class ClassTemplatePartialSpecializationDecl
return K == ClassTemplatePartialSpecialization;
}
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
return true;
}
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
@ -1886,7 +1946,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ClassTemplateDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ClassTemplate; }
friend class ASTDeclReader;
@ -1984,7 +2043,6 @@ class FriendTemplateDecl : public Decl {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Decl::FriendTemplate; }
static bool classof(const FriendTemplateDecl *D) { return true; }
friend class ASTDeclReader;
};
@ -2059,7 +2117,6 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TypeAliasTemplate; }
friend class ASTDeclReader;
@ -2123,9 +2180,6 @@ class ClassScopeFunctionSpecializationDecl : public Decl {
static bool classofKind(Kind K) {
return K == Decl::ClassScopeFunctionSpecialization;
}
static bool classof(const ClassScopeFunctionSpecializationDecl *D) {
return true;
}
friend class ASTDeclReader;
friend class ASTDeclWriter;

View File

@ -334,8 +334,8 @@ class DeclarationNameTable {
CXXOperatorIdName *CXXOperatorNames; // Operator names
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
DeclarationNameTable(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
void operator=(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
public:
DeclarationNameTable(const ASTContext &C);

View File

@ -34,6 +34,7 @@
namespace clang {
class ASTContext;
class APValue;
class CastExpr;
class Decl;
class IdentifierInfo;
class ParmVarDecl;
@ -42,6 +43,7 @@ namespace clang {
class BlockDecl;
class CXXBaseSpecifier;
class CXXOperatorCallExpr;
class MaterializeTemporaryExpr;
class CXXMemberCallExpr;
class ObjCPropertyRefExpr;
class OpaqueValueExpr;
@ -49,6 +51,48 @@ namespace clang {
/// \brief A simple array of base specifiers.
typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
/// \brief An adjustment to be made to the temporary created when emitting a
/// reference binding, which accesses a particular subobject of that temporary.
struct SubobjectAdjustment {
enum {
DerivedToBaseAdjustment,
FieldAdjustment,
MemberPointerAdjustment
} Kind;
union {
struct {
const CastExpr *BasePath;
const CXXRecordDecl *DerivedClass;
} DerivedToBase;
FieldDecl *Field;
struct {
const MemberPointerType *MPT;
Expr *RHS;
} Ptr;
};
SubobjectAdjustment(const CastExpr *BasePath,
const CXXRecordDecl *DerivedClass)
: Kind(DerivedToBaseAdjustment) {
DerivedToBase.BasePath = BasePath;
DerivedToBase.DerivedClass = DerivedClass;
}
SubobjectAdjustment(FieldDecl *Field)
: Kind(FieldAdjustment) {
this->Field = Field;
}
SubobjectAdjustment(const MemberPointerType *MPT, Expr *RHS)
: Kind(MemberPointerAdjustment) {
this->Ptr.MPT = MPT;
this->Ptr.RHS = RHS;
}
};
/// Expr - This represents one expression. Note that Expr's are subclasses of
/// Stmt. This allows an expression to be transparently used any place a Stmt
/// is required.
@ -220,15 +264,6 @@ class Expr : public Stmt {
/// Reasons why an expression might not be an l-value.
LValueClassification ClassifyLValue(ASTContext &Ctx) const;
/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
/// does not have an incomplete type, does not have a const-qualified type,
/// and if it is a structure or union, does not have any member (including,
/// recursively, any member or element of all contained aggregates or unions)
/// with a const-qualified type.
///
/// \param Loc [in,out] - A source location which *may* be filled
/// in with the location of the expression making this a
/// non-modifiable lvalue, if specified.
enum isModifiableLvalueResult {
MLV_Valid,
MLV_NotObjectType,
@ -247,6 +282,15 @@ class Expr : public Stmt {
MLV_ClassTemporary,
MLV_ArrayTemporary
};
/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
/// does not have an incomplete type, does not have a const-qualified type,
/// and if it is a structure or union, does not have any member (including,
/// recursively, any member or element of all contained aggregates or unions)
/// with a const-qualified type.
///
/// \param Loc [in,out] - A source location which *may* be filled
/// in with the location of the expression making this a
/// non-modifiable lvalue, if specified.
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
SourceLocation *Loc = 0) const;
@ -392,6 +436,9 @@ class Expr : public Stmt {
/// property, find the underlying property reference expression.
const ObjCPropertyRefExpr *getObjCProperty() const;
/// \brief Check if this expression is the ObjC 'self' implicit parameter.
bool isObjCSelfExpr() const;
/// \brief Returns whether this expression refers to a vector element.
bool refersToVectorElement() const;
@ -692,11 +739,22 @@ class Expr : public Stmt {
/// behavior if the object isn't dynamically of the derived type.
const CXXRecordDecl *getBestDynamicClassType() const;
/// Walk outwards from an expression we want to bind a reference to and
/// find the expression whose lifetime needs to be extended. Record
/// the adjustments needed along the path.
const Expr *
skipRValueSubobjectAdjustments(
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
/// Skip irrelevant expressions to find what should be materialize for
/// binding with a reference.
const Expr *
findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const;
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstExprConstant &&
T->getStmtClass() <= lastExprConstant;
}
static bool classof(const Expr *) { return true; }
};
@ -762,7 +820,6 @@ class OpaqueValueExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == OpaqueValueExprClass;
}
static bool classof(const OpaqueValueExpr *) { return true; }
};
/// \brief A reference to a declared variable, function, enum, etc.
@ -1059,7 +1116,6 @@ class DeclRefExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclRefExprClass;
}
static bool classof(const DeclRefExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1109,7 +1165,6 @@ class PredefinedExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == PredefinedExprClass;
}
static bool classof(const PredefinedExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1132,8 +1187,8 @@ class APNumericStorage {
bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; }
APNumericStorage(const APNumericStorage&); // do not implement
APNumericStorage& operator=(const APNumericStorage&); // do not implement
APNumericStorage(const APNumericStorage &) LLVM_DELETED_FUNCTION;
void operator=(const APNumericStorage &) LLVM_DELETED_FUNCTION;
protected:
APNumericStorage() : VAL(0), BitWidth(0) { }
@ -1196,7 +1251,6 @@ class IntegerLiteral : public Expr, public APIntStorage {
static bool classof(const Stmt *T) {
return T->getStmtClass() == IntegerLiteralClass;
}
static bool classof(const IntegerLiteral *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1243,7 +1297,6 @@ class CharacterLiteral : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CharacterLiteralClass;
}
static bool classof(const CharacterLiteral *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1286,7 +1339,6 @@ class FloatingLiteral : public Expr, private APFloatStorage {
static bool classof(const Stmt *T) {
return T->getStmtClass() == FloatingLiteralClass;
}
static bool classof(const FloatingLiteral *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1317,7 +1369,6 @@ class ImaginaryLiteral : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImaginaryLiteralClass;
}
static bool classof(const ImaginaryLiteral *) { return true; }
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
@ -1479,7 +1530,6 @@ class StringLiteral : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == StringLiteralClass;
}
static bool classof(const StringLiteral *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1520,7 +1570,6 @@ class ParenExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ParenExprClass;
}
static bool classof(const ParenExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
@ -1610,7 +1659,7 @@ class UnaryOperator : public Expr {
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "sizeof" or "[pre]++"
static const char *getOpcodeStr(Opcode Op);
static StringRef getOpcodeStr(Opcode Op);
/// \brief Retrieve the unary opcode that corresponds to the given
/// overloaded operator.
@ -1631,7 +1680,6 @@ class UnaryOperator : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryOperatorClass;
}
static bool classof(const UnaryOperator *) { return true; }
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
@ -1757,8 +1805,7 @@ class OffsetOfExpr : public Expr {
OffsetOfExpr(ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
OffsetOfNode* compsPtr, unsigned numComps,
Expr** exprsPtr, unsigned numExprs,
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
SourceLocation RParenLoc);
explicit OffsetOfExpr(unsigned numComps, unsigned numExprs)
@ -1769,9 +1816,8 @@ class OffsetOfExpr : public Expr {
static OffsetOfExpr *Create(ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
OffsetOfNode* compsPtr, unsigned numComps,
Expr** exprsPtr, unsigned numExprs,
SourceLocation RParenLoc);
ArrayRef<OffsetOfNode> comps,
ArrayRef<Expr*> exprs, SourceLocation RParenLoc);
static OffsetOfExpr *CreateEmpty(ASTContext &C,
unsigned NumComps, unsigned NumExprs);
@ -1832,8 +1878,6 @@ class OffsetOfExpr : public Expr {
return T->getStmtClass() == OffsetOfExprClass;
}
static bool classof(const OffsetOfExpr *) { return true; }
// Iterators
child_range children() {
Stmt **begin =
@ -1937,7 +1981,6 @@ class UnaryExprOrTypeTraitExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryExprOrTypeTraitExprClass;
}
static bool classof(const UnaryExprOrTypeTraitExpr *) { return true; }
// Iterators
child_range children();
@ -2017,7 +2060,6 @@ class ArraySubscriptExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ArraySubscriptExprClass;
}
static bool classof(const ArraySubscriptExpr *) { return true; }
// Iterators
child_range children() {
@ -2041,7 +2083,7 @@ class CallExpr : public Expr {
protected:
// These versions of the constructor are for derived classes.
CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
Expr **args, unsigned numargs, QualType t, ExprValueKind VK,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation rparenloc);
CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty);
@ -2061,7 +2103,7 @@ class CallExpr : public Expr {
unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; }
public:
CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t,
CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t,
ExprValueKind VK, SourceLocation rparenloc);
/// \brief Build an empty call expression.
@ -2153,7 +2195,6 @@ class CallExpr : public Expr {
return T->getStmtClass() >= firstCallExprConstant &&
T->getStmtClass() <= lastCallExprConstant;
}
static bool classof(const CallExpr *) { return true; }
// Iterators
child_range children() {
@ -2440,7 +2481,6 @@ class MemberExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == MemberExprClass;
}
static bool classof(const MemberExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
@ -2506,7 +2546,6 @@ class CompoundLiteralExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CompoundLiteralExprClass;
}
static bool classof(const CompoundLiteralExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Init, &Init+1); }
@ -2597,7 +2636,6 @@ class CastExpr : public Expr {
return T->getStmtClass() >= firstCastExprConstant &&
T->getStmtClass() <= lastCastExprConstant;
}
static bool classof(const CastExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Op, &Op+1); }
@ -2661,7 +2699,6 @@ class ImplicitCastExpr : public CastExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImplicitCastExprClass;
}
static bool classof(const ImplicitCastExpr *) { return true; }
};
inline Expr *Expr::IgnoreImpCasts() {
@ -2716,7 +2753,6 @@ class ExplicitCastExpr : public CastExpr {
return T->getStmtClass() >= firstExplicitCastExprConstant &&
T->getStmtClass() <= lastExplicitCastExprConstant;
}
static bool classof(const ExplicitCastExpr *) { return true; }
};
/// CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style
@ -2757,7 +2793,6 @@ class CStyleCastExpr : public ExplicitCastExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CStyleCastExprClass;
}
static bool classof(const CStyleCastExpr *) { return true; }
};
/// \brief A builtin binary operation expression such as "x + y" or "x <= y".
@ -2784,6 +2819,12 @@ class BinaryOperator : public Expr {
private:
unsigned Opc : 6;
// Records the FP_CONTRACT pragma status at the point that this binary
// operator was parsed. This bit is only meaningful for operations on
// floating point types. For all other types it should default to
// false.
unsigned FPContractable : 1;
SourceLocation OpLoc;
enum { LHS, RHS, END_EXPR };
@ -2792,7 +2833,7 @@ class BinaryOperator : public Expr {
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
ExprValueKind VK, ExprObjectKind OK,
SourceLocation opLoc)
SourceLocation opLoc, bool fpContractable)
: Expr(BinaryOperatorClass, ResTy, VK, OK,
lhs->isTypeDependent() || rhs->isTypeDependent(),
lhs->isValueDependent() || rhs->isValueDependent(),
@ -2800,7 +2841,7 @@ class BinaryOperator : public Expr {
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())),
Opc(opc), OpLoc(opLoc) {
Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
assert(!isCompoundAssignmentOp() &&
@ -2829,9 +2870,9 @@ class BinaryOperator : public Expr {
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "<<=".
static const char *getOpcodeStr(Opcode Op);
static StringRef getOpcodeStr(Opcode Op);
const char *getOpcodeStr() const { return getOpcodeStr(getOpcode()); }
StringRef getOpcodeStr() const { return getOpcodeStr(getOpcode()); }
/// \brief Retrieve the binary opcode that corresponds to the given
/// overloaded operator.
@ -2894,17 +2935,24 @@ class BinaryOperator : public Expr {
return S->getStmtClass() >= firstBinaryOperatorConstant &&
S->getStmtClass() <= lastBinaryOperatorConstant;
}
static bool classof(const BinaryOperator *) { return true; }
// Iterators
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
// Set the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
void setFPContractable(bool FPC) { FPContractable = FPC; }
// Get the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
bool isFPContractable() const { return FPContractable; }
protected:
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
ExprValueKind VK, ExprObjectKind OK,
SourceLocation opLoc, bool dead)
SourceLocation opLoc, bool fpContractable, bool dead2)
: Expr(CompoundAssignOperatorClass, ResTy, VK, OK,
lhs->isTypeDependent() || rhs->isTypeDependent(),
lhs->isValueDependent() || rhs->isValueDependent(),
@ -2912,7 +2960,7 @@ class BinaryOperator : public Expr {
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())),
Opc(opc), OpLoc(opLoc) {
Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
}
@ -2934,8 +2982,9 @@ class CompoundAssignOperator : public BinaryOperator {
CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType,
ExprValueKind VK, ExprObjectKind OK,
QualType CompLHSType, QualType CompResultType,
SourceLocation OpLoc)
: BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, true),
SourceLocation OpLoc, bool fpContractable)
: BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable,
true),
ComputationLHSType(CompLHSType),
ComputationResultType(CompResultType) {
assert(isCompoundAssignmentOp() &&
@ -2955,7 +3004,6 @@ class CompoundAssignOperator : public BinaryOperator {
QualType getComputationResultType() const { return ComputationResultType; }
void setComputationResultType(QualType T) { ComputationResultType = T; }
static bool classof(const CompoundAssignOperator *) { return true; }
static bool classof(const Stmt *S) {
return S->getStmtClass() == CompoundAssignOperatorClass;
}
@ -3001,7 +3049,6 @@ class AbstractConditionalOperator : public Expr {
return T->getStmtClass() == ConditionalOperatorClass ||
T->getStmtClass() == BinaryConditionalOperatorClass;
}
static bool classof(const AbstractConditionalOperator *) { return true; }
};
/// ConditionalOperator - The ?: ternary operator. The GNU "missing
@ -3060,7 +3107,6 @@ class ConditionalOperator : public AbstractConditionalOperator {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ConditionalOperatorClass;
}
static bool classof(const ConditionalOperator *) { return true; }
// Iterators
child_range children() {
@ -3142,7 +3188,6 @@ class BinaryConditionalOperator : public AbstractConditionalOperator {
static bool classof(const Stmt *T) {
return T->getStmtClass() == BinaryConditionalOperatorClass;
}
static bool classof(const BinaryConditionalOperator *) { return true; }
// Iterators
child_range children() {
@ -3198,7 +3243,6 @@ class AddrLabelExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == AddrLabelExprClass;
}
static bool classof(const AddrLabelExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -3242,7 +3286,6 @@ class StmtExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == StmtExprClass;
}
static bool classof(const StmtExpr *) { return true; }
// Iterators
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
@ -3266,9 +3309,8 @@ class ShuffleVectorExpr : public Expr {
unsigned NumExprs;
public:
ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr,
QualType Type, SourceLocation BLoc,
SourceLocation RP);
ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, QualType Type,
SourceLocation BLoc, SourceLocation RP);
/// \brief Build an empty vector-shuffle expression.
explicit ShuffleVectorExpr(EmptyShell Empty)
@ -3286,7 +3328,6 @@ class ShuffleVectorExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ShuffleVectorExprClass;
}
static bool classof(const ShuffleVectorExpr *) { return true; }
/// getNumSubExprs - Return the size of the SubExprs array. This includes the
/// constant expression, the actual arguments passed in, and the function
@ -3308,7 +3349,7 @@ class ShuffleVectorExpr : public Expr {
void setExprs(ASTContext &C, Expr ** Exprs, unsigned NumExprs);
unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) {
unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) const {
assert((N < NumExprs - 2) && "Shuffle idx out of range!");
return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue();
}
@ -3381,7 +3422,6 @@ class ChooseExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ChooseExprClass;
}
static bool classof(const ChooseExpr *) { return true; }
// Iterators
child_range children() {
@ -3418,7 +3458,6 @@ class GNUNullExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == GNUNullExprClass;
}
static bool classof(const GNUNullExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -3464,7 +3503,6 @@ class VAArgExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == VAArgExprClass;
}
static bool classof(const VAArgExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
@ -3501,21 +3539,32 @@ class VAArgExpr : public Expr {
/// initializer lists may still have fewer initializers than there are
/// elements to initialize within the object.
///
/// After semantic analysis has completed, given an initializer list,
/// method isSemanticForm() returns true if and only if this is the
/// semantic form of the initializer list (note: the same AST node
/// may at the same time be the syntactic form).
/// Given the semantic form of the initializer list, one can retrieve
/// the original syntactic form of that initializer list (if it
/// exists) using getSyntacticForm(). Since many initializer lists
/// have the same syntactic and semantic forms, getSyntacticForm() may
/// return NULL, indicating that the current initializer list also
/// serves as its syntactic form.
/// the syntactic form of that initializer list (when different)
/// using method getSyntacticForm(); the method returns null if applied
/// to a initializer list which is already in syntactic form.
/// Similarly, given the syntactic form (i.e., an initializer list such
/// that isSemanticForm() returns false), one can retrieve the semantic
/// form using method getSemanticForm().
/// Since many initializer lists have the same syntactic and semantic forms,
/// getSyntacticForm() may return NULL, indicating that the current
/// semantic initializer list also serves as its syntactic form.
class InitListExpr : public Expr {
// FIXME: Eliminate this vector in favor of ASTContext allocation
typedef ASTVector<Stmt *> InitExprsTy;
InitExprsTy InitExprs;
SourceLocation LBraceLoc, RBraceLoc;
/// Contains the initializer list that describes the syntactic form
/// written in the source code.
InitListExpr *SyntacticForm;
/// The alternative form of the initializer list (if it exists).
/// The int part of the pair stores whether this initalizer list is
/// in semantic form. If not null, the pointer points to:
/// - the syntactic form, if this is in semantic form;
/// - the semantic form, if this is in syntactic form.
llvm::PointerIntPair<InitListExpr *, 1, bool> AltForm;
/// \brief Either:
/// If this initializer list initializes an array with more elements than
@ -3528,8 +3577,7 @@ class InitListExpr : public Expr {
public:
InitListExpr(ASTContext &C, SourceLocation lbraceloc,
Expr **initexprs, unsigned numinits,
SourceLocation rbraceloc);
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc);
/// \brief Build an empty initializer list.
explicit InitListExpr(ASTContext &C, EmptyShell Empty)
@ -3621,12 +3669,20 @@ class InitListExpr : public Expr {
SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; }
/// @brief Retrieve the initializer list that describes the
/// syntactic form of the initializer.
///
///
InitListExpr *getSyntacticForm() const { return SyntacticForm; }
void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; }
bool isSemanticForm() const { return AltForm.getInt(); }
InitListExpr *getSemanticForm() const {
return isSemanticForm() ? 0 : AltForm.getPointer();
}
InitListExpr *getSyntacticForm() const {
return isSemanticForm() ? AltForm.getPointer() : 0;
}
void setSyntacticForm(InitListExpr *Init) {
AltForm.setPointer(Init);
AltForm.setInt(true);
Init->AltForm.setPointer(this);
Init->AltForm.setInt(false);
}
bool hadArrayRangeDesignator() const {
return InitListExprBits.HadArrayRangeDesignator != 0;
@ -3647,7 +3703,6 @@ class InitListExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == InitListExprClass;
}
static bool classof(const InitListExpr *) { return true; }
// Iterators
child_range children() {
@ -3723,8 +3778,7 @@ class DesignatedInitExpr : public Expr {
DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc, bool GNUSyntax,
Expr **IndexExprs, unsigned NumIndexExprs,
Expr *Init);
ArrayRef<Expr*> IndexExprs, Expr *Init);
explicit DesignatedInitExpr(unsigned NumSubExprs)
: Expr(DesignatedInitExprClass, EmptyShell()),
@ -3885,7 +3939,7 @@ class DesignatedInitExpr : public Expr {
static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
unsigned NumDesignators,
Expr **IndexExprs, unsigned NumIndexExprs,
ArrayRef<Expr*> IndexExprs,
SourceLocation EqualOrColonLoc,
bool GNUSyntax, Expr *Init);
@ -3985,7 +4039,6 @@ class DesignatedInitExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == DesignatedInitExprClass;
}
static bool classof(const DesignatedInitExpr *) { return true; }
// Iterators
child_range children() {
@ -4015,7 +4068,6 @@ class ImplicitValueInitExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImplicitValueInitExprClass;
}
static bool classof(const ImplicitValueInitExpr *) { return true; }
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange();
@ -4032,8 +4084,8 @@ class ParenListExpr : public Expr {
SourceLocation LParenLoc, RParenLoc;
public:
ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs,
unsigned numexprs, SourceLocation rparenloc);
ParenListExpr(ASTContext& C, SourceLocation lparenloc, ArrayRef<Expr*> exprs,
SourceLocation rparenloc);
/// \brief Build an empty paren list.
explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
@ -4061,7 +4113,6 @@ class ParenListExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ParenListExprClass;
}
static bool classof(const ParenListExpr *) { return true; }
// Iterators
child_range children() {
@ -4109,18 +4160,18 @@ class GenericSelectionExpr : public Expr {
public:
GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
TypeSourceInfo **AssocTypes, Expr **AssocExprs,
unsigned NumAssocs, SourceLocation DefaultLoc,
SourceLocation RParenLoc,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
SourceLocation DefaultLoc, SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack,
unsigned ResultIndex);
/// This constructor is used in the result-dependent case.
GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
TypeSourceInfo **AssocTypes, Expr **AssocExprs,
unsigned NumAssocs, SourceLocation DefaultLoc,
SourceLocation RParenLoc,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
SourceLocation DefaultLoc, SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack);
explicit GenericSelectionExpr(EmptyShell Empty)
@ -4176,7 +4227,6 @@ class GenericSelectionExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == GenericSelectionExprClass;
}
static bool classof(const GenericSelectionExpr *) { return true; }
child_range children() {
return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs);
@ -4247,7 +4297,6 @@ class ExtVectorElementExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ExtVectorElementExprClass;
}
static bool classof(const ExtVectorElementExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
@ -4289,7 +4338,6 @@ class BlockExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == BlockExprClass;
}
static bool classof(const BlockExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -4336,7 +4384,6 @@ class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr?
static bool classof(const Stmt *T) {
return T->getStmtClass() == AsTypeExprClass;
}
static bool classof(const AsTypeExpr *) { return true; }
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
@ -4473,7 +4520,6 @@ class PseudoObjectExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == PseudoObjectExprClass;
}
static bool classof(const PseudoObjectExpr *) { return true; }
};
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
@ -4501,7 +4547,7 @@ class AtomicExpr : public Expr {
friend class ASTStmtReader;
public:
AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, QualType t,
AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t,
AtomicOp op, SourceLocation RP);
/// \brief Determine the number of arguments the specified atomic builtin
@ -4563,7 +4609,6 @@ class AtomicExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == AtomicExprClass;
}
static bool classof(const AtomicExpr *) { return true; }
// Iterators
child_range children() {

View File

@ -53,14 +53,19 @@ class CXXOperatorCallExpr : public CallExpr {
OverloadedOperatorKind Operator;
SourceRange Range;
// Record the FP_CONTRACT state that applies to this operator call. Only
// meaningful for floating point types. For other types this value can be
// set to false.
unsigned FPContractable : 1;
SourceRange getSourceRangeImpl() const LLVM_READONLY;
public:
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
Expr **args, unsigned numargs, QualType t,
ExprValueKind VK, SourceLocation operatorloc)
: CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, numargs, t, VK,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation operatorloc, bool fpContractable)
: CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, t, VK,
operatorloc),
Operator(Op) {
Operator(Op), FPContractable(fpContractable) {
Range = getSourceRangeImpl();
}
explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
@ -83,7 +88,14 @@ class CXXOperatorCallExpr : public CallExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXOperatorCallExprClass;
}
static bool classof(const CXXOperatorCallExpr *) { return true; }
// Set the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
void setFPContractable(bool FPC) { FPContractable = FPC; }
// Get the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
bool isFPContractable() const { return FPContractable; }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@ -99,9 +111,9 @@ class CXXOperatorCallExpr : public CallExpr {
/// the object argument).
class CXXMemberCallExpr : public CallExpr {
public:
CXXMemberCallExpr(ASTContext &C, Expr *fn, Expr **args, unsigned numargs,
CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> args,
QualType t, ExprValueKind VK, SourceLocation RP)
: CallExpr(C, CXXMemberCallExprClass, fn, 0, args, numargs, t, VK, RP) {}
: CallExpr(C, CXXMemberCallExprClass, fn, 0, args, t, VK, RP) {}
CXXMemberCallExpr(ASTContext &C, EmptyShell Empty)
: CallExpr(C, CXXMemberCallExprClass, Empty) { }
@ -124,7 +136,6 @@ class CXXMemberCallExpr : public CallExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXMemberCallExprClass;
}
static bool classof(const CXXMemberCallExpr *) { return true; }
};
/// CUDAKernelCallExpr - Represents a call to a CUDA kernel function.
@ -134,10 +145,9 @@ class CUDAKernelCallExpr : public CallExpr {
public:
CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config,
Expr **args, unsigned numargs, QualType t,
ExprValueKind VK, SourceLocation RP)
: CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, numargs, t, VK,
RP) {
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation RP)
: CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, t, VK, RP) {
setConfig(Config);
}
@ -153,7 +163,6 @@ class CUDAKernelCallExpr : public CallExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CUDAKernelCallExprClass;
}
static bool classof(const CUDAKernelCallExpr *) { return true; }
};
/// CXXNamedCastExpr - Abstract class common to all of the C++ "named"
@ -205,7 +214,6 @@ class CXXNamedCastExpr : public ExplicitCastExpr {
return false;
}
}
static bool classof(const CXXNamedCastExpr *) { return true; }
};
/// CXXStaticCastExpr - A C++ @c static_cast expression
@ -235,7 +243,6 @@ class CXXStaticCastExpr : public CXXNamedCastExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXStaticCastExprClass;
}
static bool classof(const CXXStaticCastExpr *) { return true; }
};
/// CXXDynamicCastExpr - A C++ @c dynamic_cast expression
@ -269,7 +276,6 @@ class CXXDynamicCastExpr : public CXXNamedCastExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDynamicCastExprClass;
}
static bool classof(const CXXDynamicCastExpr *) { return true; }
};
/// CXXReinterpretCastExpr - A C++ @c reinterpret_cast expression (C++
@ -301,7 +307,6 @@ class CXXReinterpretCastExpr : public CXXNamedCastExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXReinterpretCastExprClass;
}
static bool classof(const CXXReinterpretCastExpr *) { return true; }
};
/// CXXConstCastExpr - A C++ @c const_cast expression (C++ [expr.const.cast]),
@ -329,7 +334,6 @@ class CXXConstCastExpr : public CXXNamedCastExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXConstCastExprClass;
}
static bool classof(const CXXConstCastExpr *) { return true; }
};
/// UserDefinedLiteral - A call to a literal operator (C++11 [over.literal])
@ -346,11 +350,11 @@ class UserDefinedLiteral : public CallExpr {
SourceLocation UDSuffixLoc;
public:
UserDefinedLiteral(ASTContext &C, Expr *Fn, Expr **Args, unsigned NumArgs,
UserDefinedLiteral(ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args,
QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
SourceLocation SuffixLoc)
: CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, NumArgs, T, VK,
LitEndLoc), UDSuffixLoc(SuffixLoc) {}
: CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, T, VK, LitEndLoc),
UDSuffixLoc(SuffixLoc) {}
explicit UserDefinedLiteral(ASTContext &C, EmptyShell Empty)
: CallExpr(C, UserDefinedLiteralClass, Empty) {}
@ -398,7 +402,6 @@ class UserDefinedLiteral : public CallExpr {
static bool classof(const Stmt *S) {
return S->getStmtClass() == UserDefinedLiteralClass;
}
static bool classof(const UserDefinedLiteral *) { return true; }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@ -429,7 +432,6 @@ class CXXBoolLiteralExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXBoolLiteralExprClass;
}
static bool classof(const CXXBoolLiteralExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -455,7 +457,6 @@ class CXXNullPtrLiteralExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXNullPtrLiteralExprClass;
}
static bool classof(const CXXNullPtrLiteralExpr *) { return true; }
child_range children() { return child_range(); }
};
@ -536,7 +537,6 @@ class CXXTypeidExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTypeidExprClass;
}
static bool classof(const CXXTypeidExpr *) { return true; }
// Iterators
child_range children() {
@ -611,7 +611,9 @@ class CXXUuidofExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUuidofExprClass;
}
static bool classof(const CXXUuidofExpr *) { return true; }
/// Grabs __declspec(uuid()) off a type, or returns 0 if there is none.
static UuidAttr *GetUuidAttrOfType(QualType QT);
// Iterators
child_range children() {
@ -659,7 +661,6 @@ class CXXThisExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThisExprClass;
}
static bool classof(const CXXThisExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -710,7 +711,6 @@ class CXXThrowExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThrowExprClass;
}
static bool classof(const CXXThrowExpr *) { return true; }
// Iterators
child_range children() {
@ -798,7 +798,6 @@ class CXXDefaultArgExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDefaultArgExprClass;
}
static bool classof(const CXXDefaultArgExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -875,7 +874,6 @@ class CXXBindTemporaryExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXBindTemporaryExprClass;
}
static bool classof(const CXXBindTemporaryExpr *) { return true; }
// Iterators
child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
@ -908,7 +906,7 @@ class CXXConstructExpr : public Expr {
CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *d, bool elidable,
Expr **args, unsigned numargs,
ArrayRef<Expr *> Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
@ -934,7 +932,7 @@ class CXXConstructExpr : public Expr {
static CXXConstructExpr *Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
ArrayRef<Expr *> Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
@ -1011,7 +1009,6 @@ class CXXConstructExpr : public Expr {
return T->getStmtClass() == CXXConstructExprClass ||
T->getStmtClass() == CXXTemporaryObjectExprClass;
}
static bool classof(const CXXConstructExpr *) { return true; }
// Iterators
child_range children() {
@ -1066,7 +1063,6 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXFunctionalCastExprClass;
}
static bool classof(const CXXFunctionalCastExpr *) { return true; }
};
/// @brief Represents a C++ functional cast expression that builds a
@ -1090,7 +1086,7 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
public:
CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
Expr **Args,unsigned NumArgs,
ArrayRef<Expr *> Args,
SourceRange parenRange,
bool HadMultipleCandidates,
bool ZeroInitialization = false);
@ -1104,7 +1100,6 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTemporaryObjectExprClass;
}
static bool classof(const CXXTemporaryObjectExpr *) { return true; }
friend class ASTStmtReader;
};
@ -1281,8 +1276,11 @@ class LambdaExpr : public Expr {
/// \brief Retrieve the complete set of array-index variables.
VarDecl **getArrayIndexVars() const {
unsigned ArrayIndexSize =
llvm::RoundUpToAlignment(sizeof(unsigned) * (NumCaptures + 1),
llvm::alignOf<VarDecl*>());
return reinterpret_cast<VarDecl **>(
getArrayIndexStarts() + NumCaptures + 1);
reinterpret_cast<char*>(getArrayIndexStarts()) + ArrayIndexSize);
}
public:
@ -1394,7 +1392,6 @@ class LambdaExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == LambdaExprClass;
}
static bool classof(const LambdaExpr *) { return true; }
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(IntroducerRange.getBegin(), ClosingBrace);
@ -1442,7 +1439,6 @@ class CXXScalarValueInitExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXScalarValueInitExprClass;
}
static bool classof(const CXXScalarValueInitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1467,8 +1463,8 @@ class CXXNewExpr : public Expr {
/// the source range covering the parenthesized type-id.
SourceRange TypeIdParens;
/// \brief Location of the first token.
SourceLocation StartLoc;
/// \brief Range of the entire new expression.
SourceRange Range;
/// \brief Source-range of a paren-delimited initializer.
SourceRange DirectInitRange;
@ -1498,11 +1494,11 @@ class CXXNewExpr : public Expr {
CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
Expr **placementArgs, unsigned numPlaceArgs,
ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
InitializationStyle initializationStyle, Expr *initializer,
QualType ty, TypeSourceInfo *AllocatedTypeInfo,
SourceLocation startLoc, SourceRange directInitRange);
SourceRange Range, SourceRange directInitRange);
explicit CXXNewExpr(EmptyShell Shell)
: Expr(CXXNewExprClass, Shell), SubExprs(0) { }
@ -1580,7 +1576,7 @@ class CXXNewExpr : public Expr {
}
/// \brief Returns the CXXConstructExpr from this new-expression, or NULL.
const CXXConstructExpr* getConstructExpr() {
const CXXConstructExpr* getConstructExpr() const {
return dyn_cast_or_null<CXXConstructExpr>(getInitializer());
}
@ -1617,19 +1613,18 @@ class CXXNewExpr : public Expr {
return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
}
SourceLocation getStartLoc() const { return StartLoc; }
SourceLocation getEndLoc() const;
SourceLocation getStartLoc() const { return Range.getBegin(); }
SourceLocation getEndLoc() const { return Range.getEnd(); }
SourceRange getDirectInitRange() const { return DirectInitRange; }
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getStartLoc(), getEndLoc());
return Range;
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXNewExprClass;
}
static bool classof(const CXXNewExpr *) { return true; }
// Iterators
child_range children() {
@ -1700,7 +1695,6 @@ class CXXDeleteExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDeleteExprClass;
}
static bool classof(const CXXDeleteExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Argument, &Argument+1); }
@ -1889,7 +1883,6 @@ class CXXPseudoDestructorExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXPseudoDestructorExprClass;
}
static bool classof(const CXXPseudoDestructorExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base + 1); }
@ -1945,7 +1938,6 @@ class UnaryTypeTraitExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryTypeTraitExprClass;
}
static bool classof(const UnaryTypeTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -2017,7 +2009,6 @@ class BinaryTypeTraitExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == BinaryTypeTraitExprClass;
}
static bool classof(const BinaryTypeTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -2111,7 +2102,6 @@ class TypeTraitExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == TypeTraitExprClass;
}
static bool classof(const TypeTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -2186,7 +2176,6 @@ class ArrayTypeTraitExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ArrayTypeTraitExprClass;
}
static bool classof(const ArrayTypeTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -2245,7 +2234,6 @@ class ExpressionTraitExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ExpressionTraitExprClass;
}
static bool classof(const ExpressionTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -2432,7 +2420,6 @@ class OverloadExpr : public Expr {
return T->getStmtClass() == UnresolvedLookupExprClass ||
T->getStmtClass() == UnresolvedMemberExprClass;
}
static bool classof(const OverloadExpr *) { return true; }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@ -2454,10 +2441,6 @@ class UnresolvedLookupExpr : public OverloadExpr {
/// call.
bool RequiresADL;
/// True if namespace ::std should be considered an associated namespace
/// for the purposes of argument-dependent lookup. See C++0x [stmt.ranged]p1.
bool StdIsAssociatedNamespace;
/// True if these lookup results are overloaded. This is pretty
/// trivially rederivable if we urgently need to kill this field.
bool Overloaded;
@ -2476,19 +2459,16 @@ class UnresolvedLookupExpr : public OverloadExpr {
const DeclarationNameInfo &NameInfo,
bool RequiresADL, bool Overloaded,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool StdIsAssociatedNamespace)
UnresolvedSetIterator Begin, UnresolvedSetIterator End)
: OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc,
NameInfo, TemplateArgs, Begin, End, false, false, false),
RequiresADL(RequiresADL),
StdIsAssociatedNamespace(StdIsAssociatedNamespace),
Overloaded(Overloaded), NamingClass(NamingClass)
{}
UnresolvedLookupExpr(EmptyShell Empty)
: OverloadExpr(UnresolvedLookupExprClass, Empty),
RequiresADL(false), StdIsAssociatedNamespace(false), Overloaded(false),
NamingClass(0)
RequiresADL(false), Overloaded(false), NamingClass(0)
{}
friend class ASTStmtReader;
@ -2500,14 +2480,10 @@ class UnresolvedLookupExpr : public OverloadExpr {
const DeclarationNameInfo &NameInfo,
bool ADL, bool Overloaded,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End,
bool StdIsAssociatedNamespace = false) {
assert((ADL || !StdIsAssociatedNamespace) &&
"std considered associated namespace when not performing ADL");
UnresolvedSetIterator End) {
return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
SourceLocation(), NameInfo,
ADL, Overloaded, 0, Begin, End,
StdIsAssociatedNamespace);
ADL, Overloaded, 0, Begin, End);
}
static UnresolvedLookupExpr *Create(ASTContext &C,
@ -2528,10 +2504,6 @@ class UnresolvedLookupExpr : public OverloadExpr {
/// argument-dependent lookup.
bool requiresADL() const { return RequiresADL; }
/// True if namespace \::std should be artificially added to the set of
/// associated namespaces for argument-dependent lookup purposes.
bool isStdAssociatedNamespace() const { return StdIsAssociatedNamespace; }
/// True if this lookup is overloaded.
bool isOverloaded() const { return Overloaded; }
@ -2554,7 +2526,6 @@ class UnresolvedLookupExpr : public OverloadExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnresolvedLookupExprClass;
}
static bool classof(const UnresolvedLookupExpr *) { return true; }
};
/// \brief A qualified reference to a name whose declaration cannot
@ -2705,7 +2676,6 @@ class DependentScopeDeclRefExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == DependentScopeDeclRefExprClass;
}
static bool classof(const DependentScopeDeclRefExpr *) { return true; }
child_range children() { return child_range(); }
@ -2778,7 +2748,6 @@ class ExprWithCleanups : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ExprWithCleanupsClass;
}
static bool classof(const ExprWithCleanups *) { return true; }
// Iterators
child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
@ -2820,8 +2789,7 @@ class CXXUnresolvedConstructExpr : public Expr {
CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
SourceLocation LParenLoc,
Expr **Args,
unsigned NumArgs,
ArrayRef<Expr*> Args,
SourceLocation RParenLoc);
CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs)
@ -2833,8 +2801,7 @@ class CXXUnresolvedConstructExpr : public Expr {
static CXXUnresolvedConstructExpr *Create(ASTContext &C,
TypeSourceInfo *Type,
SourceLocation LParenLoc,
Expr **Args,
unsigned NumArgs,
ArrayRef<Expr*> Args,
SourceLocation RParenLoc);
static CXXUnresolvedConstructExpr *CreateEmpty(ASTContext &C,
@ -2893,7 +2860,6 @@ class CXXUnresolvedConstructExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUnresolvedConstructExprClass;
}
static bool classof(const CXXUnresolvedConstructExpr *) { return true; }
// Iterators
child_range children() {
@ -3142,7 +3108,6 @@ class CXXDependentScopeMemberExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDependentScopeMemberExprClass;
}
static bool classof(const CXXDependentScopeMemberExpr *) { return true; }
// Iterators
child_range children() {
@ -3276,7 +3241,6 @@ class UnresolvedMemberExpr : public OverloadExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnresolvedMemberExprClass;
}
static bool classof(const UnresolvedMemberExpr *) { return true; }
// Iterators
child_range children() {
@ -3320,7 +3284,6 @@ class CXXNoexceptExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXNoexceptExprClass;
}
static bool classof(const CXXNoexceptExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Operand, &Operand + 1); }
@ -3397,7 +3360,6 @@ class PackExpansionExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == PackExpansionExprClass;
}
static bool classof(const PackExpansionExpr *) { return true; }
// Iterators
child_range children() {
@ -3503,7 +3465,6 @@ class SizeOfPackExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == SizeOfPackExprClass;
}
static bool classof(const SizeOfPackExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -3548,9 +3509,6 @@ class SubstNonTypeTemplateParmExpr : public Expr {
static bool classof(const Stmt *s) {
return s->getStmtClass() == SubstNonTypeTemplateParmExprClass;
}
static bool classof(const SubstNonTypeTemplateParmExpr *) {
return true;
}
// Iterators
child_range children() { return child_range(&Replacement, &Replacement+1); }
@ -3561,7 +3519,7 @@ class SubstNonTypeTemplateParmExpr : public Expr {
///
/// When a pack expansion in the source code contains multiple parameter packs
/// and those parameter packs correspond to different levels of template
/// parameter lists, this node node is used to represent a non-type template
/// parameter lists, this node is used to represent a non-type template
/// parameter pack from an outer level, which has already had its argument pack
/// substituted but that still lives within a pack expansion that itself
/// could not be instantiated. When actually performing a substitution into
@ -3608,14 +3566,77 @@ class SubstNonTypeTemplateParmPackExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass;
}
static bool classof(const SubstNonTypeTemplateParmPackExpr *) {
return true;
}
// Iterators
child_range children() { return child_range(); }
};
/// \brief Represents a reference to a function parameter pack that has been
/// substituted but not yet expanded.
///
/// When a pack expansion contains multiple parameter packs at different levels,
/// this node is used to represent a function parameter pack at an outer level
/// which we have already substituted to refer to expanded parameters, but where
/// the containing pack expansion cannot yet be expanded.
///
/// \code
/// template<typename...Ts> struct S {
/// template<typename...Us> auto f(Ts ...ts) -> decltype(g(Us(ts)...));
/// };
/// template struct S<int, int>;
/// \endcode
class FunctionParmPackExpr : public Expr {
/// \brief The function parameter pack which was referenced.
ParmVarDecl *ParamPack;
/// \brief The location of the function parameter pack reference.
SourceLocation NameLoc;
/// \brief The number of expansions of this pack.
unsigned NumParameters;
FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
SourceLocation NameLoc, unsigned NumParams,
Decl * const *Params);
friend class ASTReader;
friend class ASTStmtReader;
public:
static FunctionParmPackExpr *Create(ASTContext &Context, QualType T,
ParmVarDecl *ParamPack,
SourceLocation NameLoc,
llvm::ArrayRef<Decl*> Params);
static FunctionParmPackExpr *CreateEmpty(ASTContext &Context,
unsigned NumParams);
/// \brief Get the parameter pack which this expression refers to.
ParmVarDecl *getParameterPack() const { return ParamPack; }
/// \brief Get the location of the parameter pack.
SourceLocation getParameterPackLocation() const { return NameLoc; }
/// \brief Iterators over the parameters which the parameter pack expanded
/// into.
typedef ParmVarDecl * const *iterator;
iterator begin() const { return reinterpret_cast<iterator>(this+1); }
iterator end() const { return begin() + NumParameters; }
/// \brief Get the number of parameters in this parameter pack.
unsigned getNumExpansions() const { return NumParameters; }
/// \brief Get an expansion of the parameter pack by index.
ParmVarDecl *getExpansion(unsigned I) const { return begin()[I]; }
SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == FunctionParmPackExprClass;
}
child_range children() { return child_range(); }
};
/// \brief Represents a prvalue temporary that written into memory so that
/// a reference can bind to it.
///
@ -3670,9 +3691,6 @@ class MaterializeTemporaryExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == MaterializeTemporaryExprClass;
}
static bool classof(const MaterializeTemporaryExpr *) {
return true;
}
// Iterators
child_range children() { return child_range(&Temporary, &Temporary + 1); }

View File

@ -51,7 +51,6 @@ class ObjCStringLiteral : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCStringLiteralClass;
}
static bool classof(const ObjCStringLiteral *) { return true; }
// Iterators
child_range children() { return child_range(&String, &String+1); }
@ -81,7 +80,6 @@ class ObjCBoolLiteralExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCBoolLiteralExprClass;
}
static bool classof(const ObjCBoolLiteralExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -121,7 +119,6 @@ class ObjCBoxedExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCBoxedExprClass;
}
static bool classof(const ObjCBoxedExpr *) { return true; }
// Iterators
child_range children() { return child_range(&SubExpr, &SubExpr+1); }
@ -156,7 +153,6 @@ class ObjCArrayLiteral : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCArrayLiteralClass;
}
static bool classof(const ObjCArrayLiteral *) { return true; }
/// \brief Retrieve elements of array of literals.
Expr **getElements() { return reinterpret_cast<Expr **>(this + 1); }
@ -319,7 +315,6 @@ class ObjCDictionaryLiteral : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCDictionaryLiteralClass;
}
static bool classof(const ObjCDictionaryLiteral *) { return true; }
// Iterators
child_range children() {
@ -372,7 +367,6 @@ class ObjCEncodeExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCEncodeExprClass;
}
static bool classof(const ObjCEncodeExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -409,7 +403,6 @@ class ObjCSelectorExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCSelectorExprClass;
}
static bool classof(const ObjCSelectorExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -447,7 +440,6 @@ class ObjCProtocolExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCProtocolExprClass;
}
static bool classof(const ObjCProtocolExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -501,7 +493,6 @@ class ObjCIvarRefExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCIvarRefExprClass;
}
static bool classof(const ObjCIvarRefExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
@ -715,7 +706,6 @@ class ObjCPropertyRefExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCPropertyRefExprClass;
}
static bool classof(const ObjCPropertyRefExpr *) { return true; }
// Iterators
child_range children() {
@ -813,7 +803,6 @@ class ObjCSubscriptRefExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCSubscriptRefExprClass;
}
static bool classof(const ObjCSubscriptRefExpr *) { return true; }
Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); }
void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; }
@ -1156,10 +1145,8 @@ class ObjCMessageExpr : public Expr {
return getReceiverKind() == Class || getReceiverKind() == SuperClass;
}
/// \brief Returns the receiver of an instance message.
///
/// \brief Returns the object expression for an instance message, or
/// NULL for a message that is not an instance message.
/// \brief Returns the object expression (receiver) for an instance message,
/// or null for a message that is not an instance message.
Expr *getInstanceReceiver() {
if (getReceiverKind() == Instance)
return static_cast<Expr *>(getReceiverPointer());
@ -1208,6 +1195,17 @@ class ObjCMessageExpr : public Expr {
return SourceLocation();
}
/// \brief Retrieve the receiver type to which this message is being directed.
///
/// This routine cross-cuts all of the different kinds of message
/// sends to determine what the underlying (statically known) type
/// of the receiver will be; use \c getReceiverKind() to determine
/// whether the message is a class or an instance method, whether it
/// is a send to super or not, etc.
///
/// \returns The type of the receiver.
QualType getReceiverType() const;
/// \brief Retrieve the Objective-C interface to which this message
/// is being directed, if known.
///
@ -1344,7 +1342,6 @@ class ObjCMessageExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCMessageExprClass;
}
static bool classof(const ObjCMessageExpr *) { return true; }
// Iterators
child_range children();
@ -1409,7 +1406,6 @@ class ObjCIsaExpr : public Expr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCIsaExprClass;
}
static bool classof(const ObjCIsaExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
@ -1483,7 +1479,6 @@ class ObjCIndirectCopyRestoreExpr : public Expr {
static bool classof(const Stmt *s) {
return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass;
}
static bool classof(const ObjCIndirectCopyRestoreExpr *) { return true; }
};
/// \brief An Objective-C "bridged" cast expression, which casts between
@ -1532,8 +1527,6 @@ class ObjCBridgedCastExpr : public ExplicitCastExpr {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCBridgedCastExprClass;
}
static bool classof(const ObjCBridgedCastExpr *) { return true; }
};
} // end namespace clang

View File

@ -162,7 +162,7 @@ class ExternalASTSource {
}
/// \brief Get the decls that are contained in a file in the Offset/Length
/// range. \arg Length can be 0 to indicate a point at \arg Offset instead of
/// range. \p Length can be 0 to indicate a point at \p Offset instead of
/// a range.
virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length,
SmallVectorImpl<Decl *> &Decls) {}

View File

@ -1,6 +1,8 @@
CLANG_LEVEL := ../../..
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc CommentNodes.inc
BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc \
CommentNodes.inc CommentHTMLTags.inc \
CommentHTMLTagsProperties.inc CommentCommandInfo.inc
TABLEGEN_INC_FILES_COMMON = 1
@ -33,3 +35,18 @@ $(ObjDir)/CommentNodes.inc.tmp : $(TD_SRC_DIR)/CommentNodes.td $(CLANG_TBLGEN) \
$(Echo) "Building Clang comment node tables with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-comment-nodes -o $(call SYSPATH, $@) $<
$(ObjDir)/CommentHTMLTags.inc.tmp : $(PROJ_SRC_DIR)/CommentHTMLTags.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang comment HTML tag matchers with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-comment-html-tags -o $(call SYSPATH, $@) $<
$(ObjDir)/CommentHTMLTagsProperties.inc.tmp : $(PROJ_SRC_DIR)/CommentHTMLTags.td \
$(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang comment HTML tag properties with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-comment-html-tags-properties -o $(call SYSPATH, $@) $<
$(ObjDir)/CommentCommandInfo.inc.tmp : $(PROJ_SRC_DIR)/CommentCommands.td \
$(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang comment command info with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-comment-command-info -o $(call SYSPATH, $@) $<

View File

@ -83,7 +83,7 @@ class NSAPI {
/// \brief The Objective-C NSArray selectors.
Selector getNSArraySelector(NSArrayMethodKind MK) const;
/// \brief Return NSArrayMethodKind if \arg Sel is such a selector.
/// \brief Return NSArrayMethodKind if \p Sel is such a selector.
llvm::Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel);
/// \brief Enumerates the NSDictionary methods used to generate literals.
@ -104,7 +104,7 @@ class NSAPI {
/// \brief The Objective-C NSDictionary selectors.
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
/// \brief Return NSDictionaryMethodKind if \arg Sel is such a selector.
/// \brief Return NSDictionaryMethodKind if \p Sel is such a selector.
llvm::Optional<NSDictionaryMethodKind>
getNSDictionaryMethodKind(Selector Sel);
@ -169,7 +169,7 @@ class NSAPI {
Sel == getNSNumberLiteralSelector(MK, true);
}
/// \brief Return NSNumberLiteralMethodKind if \arg Sel is such a selector.
/// \brief Return NSNumberLiteralMethodKind if \p Sel is such a selector.
llvm::Optional<NSNumberLiteralMethodKind>
getNSNumberLiteralMethodKind(Selector Sel) const;

View File

@ -97,8 +97,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
Specifier(Other.Specifier) {
}
NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not
// implement
void operator=(const NestedNameSpecifier &) LLVM_DELETED_FUNCTION;
/// \brief Either find or insert the given nested name specifier
/// mockup in the given context.

View File

@ -288,7 +288,11 @@ enum CastKind {
///
/// This particular cast kind is used for the conversion from a C++11
/// lambda expression to a block pointer.
CK_CopyAndAutoreleaseBlockObject
CK_CopyAndAutoreleaseBlockObject,
// Convert a builtin function to a function pointer; only allowed in the
// callee of a call expression.
CK_BuiltinFnToFnPtr
};
static const CastKind CK_Invalid = static_cast<CastKind>(-1);

View File

@ -39,6 +39,7 @@ struct PrintingPolicy {
SuppressUnwrittenScope(false), SuppressInitializers(false),
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
SuppressStrongLifetime(false), Bool(LO.Bool),
TerseOutput(false), SuppressAttributes(false),
DumpSourceManager(0) { }
/// \brief What language we're printing.
@ -134,6 +135,17 @@ struct PrintingPolicy {
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
unsigned Bool : 1;
/// \brief Provide a 'terse' output.
///
/// For example, in this mode we don't print function bodies, class members,
/// declarations inside namespaces etc. Effectively, this should print
/// only the requested declaration.
unsigned TerseOutput : 1;
/// \brief When true, do not print attributes attached to the declaration.
///
unsigned SuppressAttributes : 1;
/// \brief If we are "dumping" rather than "pretty-printing", this points to
/// a SourceManager which will be used to dump SourceLocations. Dumping
/// involves printing the internal details of the AST and pretty-printing

View File

@ -18,6 +18,7 @@ namespace clang {
class ASTContext;
class ASTReader;
class Decl;
class Preprocessor;
namespace comments {
class FullComment;
@ -114,7 +115,8 @@ class RawComment {
}
/// Parse the comment, assuming it is attached to decl \c D.
comments::FullComment *parse(const ASTContext &Context, const Decl *D) const;
comments::FullComment *parse(const ASTContext &Context,
const Preprocessor *PP, const Decl *D) const;
private:
SourceRange Range;
@ -188,7 +190,7 @@ class RawCommentList {
private:
SourceManager &SourceMgr;
std::vector<RawComment *> Comments;
RawComment LastComment;
SourceLocation PrevCommentEndLoc;
bool OnlyWhitespaceSeen;
void addCommentsToFront(const std::vector<RawComment *> &C) {

View File

@ -136,8 +136,8 @@ class ASTRecordLayout {
void Destroy(ASTContext &Ctx);
ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT
void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT
ASTRecordLayout(const ASTRecordLayout &) LLVM_DELETED_FUNCTION;
void operator=(const ASTRecordLayout &) LLVM_DELETED_FUNCTION;
public:
/// getAlignment - Get the record alignment in characters.

View File

@ -721,6 +721,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
return true;
case TemplateArgument::Type:
@ -753,6 +754,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
return true;
case TemplateArgument::Type: {
@ -799,7 +801,7 @@ bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo())
TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
if (Init->isWritten())
if (Init->isWritten() || getDerived().shouldVisitImplicitCode())
TRY_TO(TraverseStmt(Init->getInit()));
return true;
}
@ -1827,7 +1829,7 @@ bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) { \
return true; \
}
DEF_TRAVERSE_STMT(AsmStmt, {
DEF_TRAVERSE_STMT(GCCAsmStmt, {
TRY_TO(TraverseStmt(S->getAsmString()));
for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
TRY_TO(TraverseStmt(S->getInputConstraintLiteral(I)));
@ -1836,7 +1838,7 @@ DEF_TRAVERSE_STMT(AsmStmt, {
TRY_TO(TraverseStmt(S->getOutputConstraintLiteral(I)));
}
for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
TRY_TO(TraverseStmt(S->getClobber(I)));
TRY_TO(TraverseStmt(S->getClobberStringLiteral(I)));
}
// children() iterates over inputExpr and outputExpr.
})
@ -2141,7 +2143,9 @@ DEF_TRAVERSE_STMT(BlockExpr, {
return true; // no child statements to loop through.
})
DEF_TRAVERSE_STMT(ChooseExpr, { })
DEF_TRAVERSE_STMT(CompoundLiteralExpr, { })
DEF_TRAVERSE_STMT(CompoundLiteralExpr, {
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
})
DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { })
DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { })
DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
@ -2219,6 +2223,7 @@ DEF_TRAVERSE_STMT(PackExpansionExpr, { })
DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
DEF_TRAVERSE_STMT(FunctionParmPackExpr, { })
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
DEF_TRAVERSE_STMT(AtomicExpr, { })

View File

@ -42,7 +42,7 @@ enum SelectorLocationsKind {
SelLoc_StandardWithSpace = 2
};
/// \brief Returns true if all \arg SelLocs are in a "standard" location.
/// \brief Returns true if all \p SelLocs are in a "standard" location.
SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
ArrayRef<SourceLocation> SelLocs,
ArrayRef<Expr *> Args,
@ -60,7 +60,7 @@ SourceLocation getStandardSelectorLoc(unsigned Index,
ArrayRef<Expr *> Args,
SourceLocation EndLoc);
/// \brief Returns true if all \arg SelLocs are in a "standard" location.
/// \brief Returns true if all \p SelLocs are in a "standard" location.
SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
ArrayRef<SourceLocation> SelLocs,
ArrayRef<ParmVarDecl *> Args,

View File

@ -392,9 +392,6 @@ class Stmt {
const_cast<const Stmt*>(this)->stripLabelLikeStatements());
}
// Implement isa<T> support.
static bool classof(const Stmt *) { return true; }
/// hasImplicitControlFlow - Some statements (e.g. short circuited operations)
/// contain implicit control-flow in the order their subexpressions
/// are evaluated. This predicate returns true if this statement has
@ -424,12 +421,12 @@ class Stmt {
/// \brief Produce a unique representation of the given statement.
///
/// \brief ID once the profiling operation is complete, will contain
/// \param ID once the profiling operation is complete, will contain
/// the unique representation of the given statement.
///
/// \brief Context the AST context in which the statement resides
/// \param Context the AST context in which the statement resides
///
/// \brief Canonical whether the profile should be based on the canonical
/// \param Canonical whether the profile should be based on the canonical
/// representation of this statement (e.g., where non-type template
/// parameters are identified by index/level rather than their
/// declaration pointers) or the exact representation of the statement as
@ -480,7 +477,6 @@ class DeclStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclStmtClass;
}
static bool classof(const DeclStmt *) { return true; }
// Iterators over subexpressions.
child_range children() {
@ -535,7 +531,6 @@ class NullStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == NullStmtClass;
}
static bool classof(const NullStmt *) { return true; }
child_range children() { return child_range(); }
@ -615,7 +610,6 @@ class CompoundStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CompoundStmtClass;
}
static bool classof(const CompoundStmt *) { return true; }
// Iterators
child_range children() {
@ -654,7 +648,6 @@ class SwitchCase : public Stmt {
return T->getStmtClass() == CaseStmtClass ||
T->getStmtClass() == DefaultStmtClass;
}
static bool classof(const SwitchCase *) { return true; }
};
class CaseStmt : public SwitchCase {
@ -714,7 +707,6 @@ class CaseStmt : public SwitchCase {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CaseStmtClass;
}
static bool classof(const CaseStmt *) { return true; }
// Iterators
child_range children() {
@ -749,7 +741,6 @@ class DefaultStmt : public SwitchCase {
static bool classof(const Stmt *T) {
return T->getStmtClass() == DefaultStmtClass;
}
static bool classof(const DefaultStmt *) { return true; }
// Iterators
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
@ -788,7 +779,6 @@ class LabelStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == LabelStmtClass;
}
static bool classof(const LabelStmt *) { return true; }
};
@ -837,7 +827,6 @@ class AttributedStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == AttributedStmtClass;
}
static bool classof(const AttributedStmt *) { return true; }
};
@ -906,7 +895,6 @@ class IfStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == IfStmtClass;
}
static bool classof(const IfStmt *) { return true; }
};
/// SwitchStmt - This represents a 'switch' stmt.
@ -1000,7 +988,6 @@ class SwitchStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == SwitchStmtClass;
}
static bool classof(const SwitchStmt *) { return true; }
};
@ -1050,7 +1037,6 @@ class WhileStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == WhileStmtClass;
}
static bool classof(const WhileStmt *) { return true; }
// Iterators
child_range children() {
@ -1099,7 +1085,6 @@ class DoStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == DoStmtClass;
}
static bool classof(const DoStmt *) { return true; }
// Iterators
child_range children() {
@ -1171,7 +1156,6 @@ class ForStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ForStmtClass;
}
static bool classof(const ForStmt *) { return true; }
// Iterators
child_range children() {
@ -1206,7 +1190,6 @@ class GotoStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == GotoStmtClass;
}
static bool classof(const GotoStmt *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1251,7 +1234,6 @@ class IndirectGotoStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == IndirectGotoStmtClass;
}
static bool classof(const IndirectGotoStmt *) { return true; }
// Iterators
child_range children() { return child_range(&Target, &Target+1); }
@ -1278,7 +1260,6 @@ class ContinueStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ContinueStmtClass;
}
static bool classof(const ContinueStmt *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1302,7 +1283,6 @@ class BreakStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == BreakStmtClass;
}
static bool classof(const BreakStmt *) { return true; }
// Iterators
child_range children() { return child_range(); }
@ -1354,7 +1334,6 @@ class ReturnStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ReturnStmtClass;
}
static bool classof(const ReturnStmt *) { return true; }
// Iterators
child_range children() {
@ -1363,48 +1342,184 @@ class ReturnStmt : public Stmt {
}
};
/// AsmStmt - This represents a GNU inline-assembly statement extension.
/// AsmStmt is the base class for GCCAsmStmt and MSAsmStmt.
///
class AsmStmt : public Stmt {
SourceLocation AsmLoc, RParenLoc;
StringLiteral *AsmStr;
protected:
SourceLocation AsmLoc;
/// \brief True if the assembly statement does not have any input or output
/// operands.
bool IsSimple;
/// \brief If true, treat this inline assembly as having side effects.
/// This assembly statement should not be optimized, deleted or moved.
bool IsVolatile;
bool MSAsm;
unsigned NumOutputs;
unsigned NumInputs;
unsigned NumClobbers;
// FIXME: If we wanted to, we could allocate all of these in one big array.
IdentifierInfo **Names;
StringLiteral **Constraints;
Stmt **Exprs;
StringLiteral **Clobbers;
AsmStmt(StmtClass SC, SourceLocation asmloc, bool issimple, bool isvolatile,
unsigned numoutputs, unsigned numinputs, unsigned numclobbers) :
Stmt (SC), AsmLoc(asmloc), IsSimple(issimple), IsVolatile(isvolatile),
NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { }
public:
AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile,
bool msasm, unsigned numoutputs, unsigned numinputs,
IdentifierInfo **names, StringLiteral **constraints,
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
StringLiteral **clobbers, SourceLocation rparenloc);
/// \brief Build an empty inline-assembly statement.
explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty),
Names(0), Constraints(0), Exprs(0), Clobbers(0) { }
explicit AsmStmt(StmtClass SC, EmptyShell Empty) :
Stmt(SC, Empty), Names(0), Exprs(0) { }
SourceLocation getAsmLoc() const { return AsmLoc; }
void setAsmLoc(SourceLocation L) { AsmLoc = L; }
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
bool isSimple() const { return IsSimple; }
void setSimple(bool V) { IsSimple = V; }
bool isVolatile() const { return IsVolatile; }
void setVolatile(bool V) { IsVolatile = V; }
bool isSimple() const { return IsSimple; }
void setSimple(bool V) { IsSimple = V; }
bool isMSAsm() const { return MSAsm; }
void setMSAsm(bool V) { MSAsm = V; }
SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(); }
//===--- Asm String Analysis ---===//
/// Assemble final IR asm string.
std::string generateAsmString(ASTContext &C) const;
//===--- Output operands ---===//
unsigned getNumOutputs() const { return NumOutputs; }
IdentifierInfo *getOutputIdentifier(unsigned i) const {
return Names[i];
}
StringRef getOutputName(unsigned i) const {
if (IdentifierInfo *II = getOutputIdentifier(i))
return II->getName();
return StringRef();
}
/// getOutputConstraint - Return the constraint string for the specified
/// output operand. All output constraints are known to be non-empty (either
/// '=' or '+').
StringRef getOutputConstraint(unsigned i) const;
/// isOutputPlusConstraint - Return true if the specified output constraint
/// is a "+" constraint (which is both an input and an output) or false if it
/// is an "=" constraint (just an output).
bool isOutputPlusConstraint(unsigned i) const {
return getOutputConstraint(i)[0] == '+';
}
const Expr *getOutputExpr(unsigned i) const;
/// getNumPlusOperands - Return the number of output operands that have a "+"
/// constraint.
unsigned getNumPlusOperands() const;
//===--- Input operands ---===//
unsigned getNumInputs() const { return NumInputs; }
IdentifierInfo *getInputIdentifier(unsigned i) const {
return Names[i + NumOutputs];
}
StringRef getInputName(unsigned i) const {
if (IdentifierInfo *II = getInputIdentifier(i))
return II->getName();
return StringRef();
}
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
StringRef getInputConstraint(unsigned i) const;
const Expr *getInputExpr(unsigned i) const;
//===--- Other ---===//
unsigned getNumClobbers() const { return NumClobbers; }
StringRef getClobber(unsigned i) const;
static bool classof(const Stmt *T) {
return T->getStmtClass() == GCCAsmStmtClass ||
T->getStmtClass() == MSAsmStmtClass;
}
// Input expr iterators.
typedef ExprIterator inputs_iterator;
typedef ConstExprIterator const_inputs_iterator;
inputs_iterator begin_inputs() {
return &Exprs[0] + NumOutputs;
}
inputs_iterator end_inputs() {
return &Exprs[0] + NumOutputs + NumInputs;
}
const_inputs_iterator begin_inputs() const {
return &Exprs[0] + NumOutputs;
}
const_inputs_iterator end_inputs() const {
return &Exprs[0] + NumOutputs + NumInputs;
}
// Output expr iterators.
typedef ExprIterator outputs_iterator;
typedef ConstExprIterator const_outputs_iterator;
outputs_iterator begin_outputs() {
return &Exprs[0];
}
outputs_iterator end_outputs() {
return &Exprs[0] + NumOutputs;
}
const_outputs_iterator begin_outputs() const {
return &Exprs[0];
}
const_outputs_iterator end_outputs() const {
return &Exprs[0] + NumOutputs;
}
child_range children() {
return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs);
}
};
/// This represents a GCC inline-assembly statement extension.
///
class GCCAsmStmt : public AsmStmt {
SourceLocation RParenLoc;
StringLiteral *AsmStr;
// FIXME: If we wanted to, we could allocate all of these in one big array.
StringLiteral **Constraints;
StringLiteral **Clobbers;
public:
GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
bool isvolatile, unsigned numoutputs, unsigned numinputs,
IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
StringLiteral *asmstr, unsigned numclobbers,
StringLiteral **clobbers, SourceLocation rparenloc);
/// \brief Build an empty inline-assembly statement.
explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty),
Constraints(0), Clobbers(0) { }
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
//===--- Asm String Analysis ---===//
@ -1461,25 +1576,11 @@ class AsmStmt : public Stmt {
unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
ASTContext &C, unsigned &DiagOffs) const;
/// Assemble final IR asm string.
std::string generateAsmString(ASTContext &C) const;
//===--- Output operands ---===//
unsigned getNumOutputs() const { return NumOutputs; }
IdentifierInfo *getOutputIdentifier(unsigned i) const {
return Names[i];
}
StringRef getOutputName(unsigned i) const {
if (IdentifierInfo *II = getOutputIdentifier(i))
return II->getName();
return StringRef();
}
/// getOutputConstraint - Return the constraint string for the specified
/// output operand. All output constraints are known to be non-empty (either
/// '=' or '+').
StringRef getOutputConstraint(unsigned i) const;
const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
@ -1492,37 +1593,11 @@ class AsmStmt : public Stmt {
Expr *getOutputExpr(unsigned i);
const Expr *getOutputExpr(unsigned i) const {
return const_cast<AsmStmt*>(this)->getOutputExpr(i);
return const_cast<GCCAsmStmt*>(this)->getOutputExpr(i);
}
/// isOutputPlusConstraint - Return true if the specified output constraint
/// is a "+" constraint (which is both an input and an output) or false if it
/// is an "=" constraint (just an output).
bool isOutputPlusConstraint(unsigned i) const {
return getOutputConstraint(i)[0] == '+';
}
/// getNumPlusOperands - Return the number of output operands that have a "+"
/// constraint.
unsigned getNumPlusOperands() const;
//===--- Input operands ---===//
unsigned getNumInputs() const { return NumInputs; }
IdentifierInfo *getInputIdentifier(unsigned i) const {
return Names[i + NumOutputs];
}
StringRef getInputName(unsigned i) const {
if (IdentifierInfo *II = getInputIdentifier(i))
return II->getName();
return StringRef();
}
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
StringRef getInputConstraint(unsigned i) const;
const StringLiteral *getInputConstraintLiteral(unsigned i) const {
@ -1536,7 +1611,7 @@ class AsmStmt : public Stmt {
void setInputExpr(unsigned i, Expr *E);
const Expr *getInputExpr(unsigned i) const {
return const_cast<AsmStmt*>(this)->getInputExpr(i);
return const_cast<GCCAsmStmt*>(this)->getInputExpr(i);
}
void setOutputsAndInputsAndClobbers(ASTContext &C,
@ -1555,90 +1630,45 @@ class AsmStmt : public Stmt {
/// This returns -1 if the operand name is invalid.
int getNamedOperand(StringRef SymbolicName) const;
unsigned getNumClobbers() const { return NumClobbers; }
StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; }
StringRef getClobber(unsigned i) const;
StringLiteral *getClobberStringLiteral(unsigned i) { return Clobbers[i]; }
const StringLiteral *getClobberStringLiteral(unsigned i) const {
return Clobbers[i];
}
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AsmLoc, RParenLoc);
}
static bool classof(const Stmt *T) {return T->getStmtClass() == AsmStmtClass;}
static bool classof(const AsmStmt *) { return true; }
// Input expr iterators.
typedef ExprIterator inputs_iterator;
typedef ConstExprIterator const_inputs_iterator;
inputs_iterator begin_inputs() {
return &Exprs[0] + NumOutputs;
}
inputs_iterator end_inputs() {
return &Exprs[0] + NumOutputs + NumInputs;
}
const_inputs_iterator begin_inputs() const {
return &Exprs[0] + NumOutputs;
}
const_inputs_iterator end_inputs() const {
return &Exprs[0] + NumOutputs + NumInputs;
}
// Output expr iterators.
typedef ExprIterator outputs_iterator;
typedef ConstExprIterator const_outputs_iterator;
outputs_iterator begin_outputs() {
return &Exprs[0];
}
outputs_iterator end_outputs() {
return &Exprs[0] + NumOutputs;
}
const_outputs_iterator begin_outputs() const {
return &Exprs[0];
}
const_outputs_iterator end_outputs() const {
return &Exprs[0] + NumOutputs;
}
child_range children() {
return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs);
static bool classof(const Stmt *T) {
return T->getStmtClass() == GCCAsmStmtClass;
}
};
/// MSAsmStmt - This represents a MS inline-assembly statement extension.
/// This represents a Microsoft inline-assembly statement extension.
///
class MSAsmStmt : public Stmt {
class MSAsmStmt : public AsmStmt {
SourceLocation AsmLoc, LBraceLoc, EndLoc;
std::string AsmStr;
bool IsSimple;
bool IsVolatile;
unsigned NumAsmToks;
unsigned NumInputs;
unsigned NumOutputs;
unsigned NumClobbers;
Token *AsmToks;
IdentifierInfo **Names;
Stmt **Exprs;
StringRef *Constraints;
StringRef *Clobbers;
public:
MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc,
bool issimple, bool isvolatile, ArrayRef<Token> asmtoks,
ArrayRef<IdentifierInfo*> inputs, ArrayRef<IdentifierInfo*> outputs,
StringRef asmstr, ArrayRef<StringRef> clobbers,
SourceLocation endloc);
unsigned numoutputs, unsigned numinputs,
ArrayRef<IdentifierInfo*> names, ArrayRef<StringRef> constraints,
ArrayRef<Expr*> exprs, StringRef asmstr,
ArrayRef<StringRef> clobbers, SourceLocation endloc);
/// \brief Build an empty MS-style inline-assembly statement.
explicit MSAsmStmt(EmptyShell Empty) : AsmStmt(MSAsmStmtClass, Empty),
NumAsmToks(0), AsmToks(0), Constraints(0), Clobbers(0) { }
SourceLocation getAsmLoc() const { return AsmLoc; }
void setAsmLoc(SourceLocation L) { AsmLoc = L; }
SourceLocation getLBraceLoc() const { return LBraceLoc; }
void setLBraceLoc(SourceLocation L) { LBraceLoc = L; }
SourceLocation getEndLoc() const { return EndLoc; }
@ -1649,20 +1679,42 @@ class MSAsmStmt : public Stmt {
unsigned getNumAsmToks() { return NumAsmToks; }
Token *getAsmToks() { return AsmToks; }
bool isVolatile() const { return IsVolatile; }
void setVolatile(bool V) { IsVolatile = V; }
bool isSimple() const { return IsSimple; }
void setSimple(bool V) { IsSimple = V; }
//===--- Asm String Analysis ---===//
const std::string *getAsmString() const { return &AsmStr; }
std::string *getAsmString() { return &AsmStr; }
void setAsmString(StringRef &E) { AsmStr = E.str(); }
/// Assemble final IR asm string.
std::string generateAsmString(ASTContext &C) const;
//===--- Output operands ---===//
StringRef getOutputConstraint(unsigned i) const {
return Constraints[i];
}
Expr *getOutputExpr(unsigned i);
const Expr *getOutputExpr(unsigned i) const {
return const_cast<MSAsmStmt*>(this)->getOutputExpr(i);
}
//===--- Input operands ---===//
StringRef getInputConstraint(unsigned i) const {
return Constraints[i + NumOutputs];
}
Expr *getInputExpr(unsigned i);
void setInputExpr(unsigned i, Expr *E);
const Expr *getInputExpr(unsigned i) const {
return const_cast<MSAsmStmt*>(this)->getInputExpr(i);
}
//===--- Other ---===//
unsigned getNumClobbers() const { return NumClobbers; }
StringRef getClobber(unsigned i) const { return Clobbers[i]; }
SourceRange getSourceRange() const LLVM_READONLY {
@ -1671,7 +1723,6 @@ class MSAsmStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == MSAsmStmtClass;
}
static bool classof(const MSAsmStmt *) { return true; }
child_range children() {
return child_range(&Exprs[0], &Exprs[0]);
@ -1720,8 +1771,6 @@ class SEHExceptStmt : public Stmt {
return T->getStmtClass() == SEHExceptStmtClass;
}
static bool classof(SEHExceptStmt *) { return true; }
};
class SEHFinallyStmt : public Stmt {
@ -1757,8 +1806,6 @@ class SEHFinallyStmt : public Stmt {
return T->getStmtClass() == SEHFinallyStmtClass;
}
static bool classof(SEHFinallyStmt *) { return true; }
};
class SEHTryStmt : public Stmt {
@ -1810,8 +1857,6 @@ class SEHTryStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == SEHTryStmtClass;
}
static bool classof(SEHTryStmt *) { return true; }
};
} // end namespace clang

View File

@ -50,7 +50,6 @@ class CXXCatchStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXCatchStmtClass;
}
static bool classof(const CXXCatchStmt *) { return true; }
child_range children() { return child_range(&HandlerBlock, &HandlerBlock+1); }
@ -111,7 +110,6 @@ class CXXTryStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTryStmtClass;
}
static bool classof(const CXXTryStmt *) { return true; }
child_range children() {
return child_range(getStmts(), getStmts() + getNumHandlers() + 1);
@ -196,7 +194,6 @@ class CXXForRangeStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXForRangeStmtClass;
}
static bool classof(const CXXForRangeStmt *) { return true; }
// Iterators
child_range children() {
@ -286,8 +283,6 @@ class MSDependentExistsStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == MSDependentExistsStmtClass;
}
static bool classof(MSDependentExistsStmt *) { return true; }
};
} // end namespace clang

View File

@ -61,7 +61,6 @@ class ObjCForCollectionStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCForCollectionStmtClass;
}
static bool classof(const ObjCForCollectionStmt *) { return true; }
// Iterators
child_range children() {
@ -112,7 +111,6 @@ class ObjCAtCatchStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtCatchStmtClass;
}
static bool classof(const ObjCAtCatchStmt *) { return true; }
child_range children() { return child_range(&Body, &Body + 1); }
};
@ -143,7 +141,6 @@ class ObjCAtFinallyStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtFinallyStmtClass;
}
static bool classof(const ObjCAtFinallyStmt *) { return true; }
child_range children() {
return child_range(&AtFinallyStmt, &AtFinallyStmt+1);
@ -244,7 +241,6 @@ class ObjCAtTryStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtTryStmtClass;
}
static bool classof(const ObjCAtTryStmt *) { return true; }
child_range children() {
return child_range(getStmts(),
@ -303,7 +299,6 @@ class ObjCAtSynchronizedStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtSynchronizedStmtClass;
}
static bool classof(const ObjCAtSynchronizedStmt *) { return true; }
child_range children() {
return child_range(&SubStmts[0], &SubStmts[0]+END_EXPR);
@ -339,7 +334,6 @@ class ObjCAtThrowStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtThrowStmtClass;
}
static bool classof(const ObjCAtThrowStmt *) { return true; }
child_range children() { return child_range(&Throw, &Throw+1); }
};
@ -371,7 +365,6 @@ class ObjCAutoreleasePoolStmt : public Stmt {
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAutoreleasePoolStmtClass;
}
static bool classof(const ObjCAutoreleasePoolStmt *) { return true; }
child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
};

View File

@ -28,11 +28,11 @@ namespace llvm {
namespace clang {
class Decl;
class DiagnosticBuilder;
class Expr;
struct PrintingPolicy;
class TypeSourceInfo;
class ValueDecl;
/// \brief Represents a template argument within a class template
/// specialization.
@ -43,12 +43,14 @@ class TemplateArgument {
/// \brief Represents an empty template argument, e.g., one that has not
/// been deduced.
Null = 0,
/// The template argument is a type. Its value is stored in the
/// TypeOrValue field.
/// The template argument is a type.
Type,
/// The template argument is a declaration that was provided for a pointer
/// or reference non-type template parameter.
/// The template argument is a declaration that was provided for a pointer,
/// reference, or pointer to member non-type template parameter.
Declaration,
/// The template argument is a null pointer or null pointer to member that
/// was provided for a non-type template parameter.
NullPtr,
/// The template argument is an integral value stored in an llvm::APSInt
/// that was provided for an integral non-type template parameter.
Integral,
@ -72,6 +74,10 @@ class TemplateArgument {
union {
uintptr_t TypeOrValue;
struct {
ValueDecl *D;
bool ForRefParam;
} DeclArg;
struct {
// We store a decomposed APSInt with the data allocated by ASTContext if
// BitWidth > 64. The memory may be shared between multiple
@ -101,15 +107,18 @@ class TemplateArgument {
TemplateArgument() : Kind(Null), TypeOrValue(0) { }
/// \brief Construct a template type argument.
TemplateArgument(QualType T) : Kind(Type) {
TemplateArgument(QualType T, bool isNullPtr = false)
: Kind(isNullPtr ? NullPtr : Type) {
TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
}
/// \brief Construct a template argument that refers to a
/// declaration, which is either an external declaration or a
/// template declaration.
TemplateArgument(Decl *D) : Kind(Declaration) {
TypeOrValue = reinterpret_cast<uintptr_t>(D);
TemplateArgument(ValueDecl *D, bool ForRefParam) : Kind(Declaration) {
assert(D && "Expected decl");
DeclArg.D = D;
DeclArg.ForRefParam = ForRefParam;
}
/// \brief Construct an integral constant template argument. The memory to
@ -177,6 +186,10 @@ class TemplateArgument {
this->Args.NumArgs = NumArgs;
}
static TemplateArgument getEmptyPack() {
return TemplateArgument((TemplateArgument*)0, 0);
}
/// \brief Create a new template argument pack by copying the given set of
/// template arguments.
static TemplateArgument CreatePackCopy(ASTContext &Context,
@ -205,34 +218,43 @@ class TemplateArgument {
/// \brief Determine whether this template argument is a pack expansion.
bool isPackExpansion() const;
/// \brief Retrieve the template argument as a type.
/// \brief Retrieve the type for a type template argument.
QualType getAsType() const {
if (Kind != Type)
return QualType();
assert(Kind == Type && "Unexpected kind");
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 declaration for a declaration non-type
/// template argument.
ValueDecl *getAsDecl() const {
assert(Kind == Declaration && "Unexpected kind");
return DeclArg.D;
}
/// \brief Retrieve the template argument as a template name.
/// \brief Retrieve whether a declaration is binding to a
/// reference parameter in a declaration non-type template argument.
bool isDeclForReferenceParam() const {
assert(Kind == Declaration && "Unexpected kind");
return DeclArg.ForRefParam;
}
/// \brief Retrieve the type for null non-type template argument.
QualType getNullPtrType() const {
assert(Kind == NullPtr && "Unexpected kind");
return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue));
}
/// \brief Retrieve the template name for a template name argument.
TemplateName getAsTemplate() const {
if (Kind != Template)
return TemplateName();
assert(Kind == Template && "Unexpected kind");
return TemplateName::getFromVoidPointer(TemplateArg.Name);
}
/// \brief Retrieve the template argument as a template name; if the argument
/// is a pack expansion, return the pattern as a template name.
TemplateName getAsTemplateOrTemplatePattern() const {
if (Kind != Template && Kind != TemplateExpansion)
return TemplateName();
assert((Kind == Template || Kind == TemplateExpansion) &&
"Unexpected kind");
return TemplateName::getFromVoidPointer(TemplateArg.Name);
}
@ -244,6 +266,7 @@ class TemplateArgument {
/// \brief Retrieve the template argument as an integral value.
// FIXME: Provide a way to read the integral data without copying the value.
llvm::APSInt getAsIntegral() const {
assert(Kind == Integral && "Unexpected kind");
using namespace llvm;
if (Integer.BitWidth <= 64)
return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned);
@ -255,23 +278,18 @@ class TemplateArgument {
/// \brief Retrieve the type of the integral value.
QualType getIntegralType() const {
if (Kind != Integral)
return QualType();
assert(Kind == Integral && "Unexpected kind");
return QualType::getFromOpaquePtr(Integer.Type);
}
void setIntegralType(QualType T) {
assert(Kind == Integral &&
"Cannot set the integral type of a non-integral template argument");
assert(Kind == Integral && "Unexpected kind");
Integer.Type = T.getAsOpaquePtr();
}
/// \brief Retrieve the template argument as an expression.
Expr *getAsExpr() const {
if (Kind != Expression)
return 0;
assert(Kind == Expression && "Unexpected kind");
return reinterpret_cast<Expr *>(TypeOrValue);
}
@ -436,7 +454,17 @@ class TemplateArgumentLoc {
assert(Argument.getKind() == TemplateArgument::Declaration);
return LocInfo.getAsExpr();
}
Expr *getSourceNullPtrExpression() const {
assert(Argument.getKind() == TemplateArgument::NullPtr);
return LocInfo.getAsExpr();
}
Expr *getSourceIntegralExpression() const {
assert(Argument.getKind() == TemplateArgument::Integral);
return LocInfo.getAsExpr();
}
NestedNameSpecifierLoc getTemplateQualifierLoc() const {
assert(Argument.getKind() == TemplateArgument::Template ||
Argument.getKind() == TemplateArgument::TemplateExpansion);

View File

@ -20,6 +20,7 @@
#include "clang/Basic/Linkage.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/Visibility.h"
#include "clang/Basic/Specifiers.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "llvm/Support/type_traits.h"
@ -160,6 +161,44 @@ class Qualifiers {
Qualifiers() : Mask(0) {}
/// \brief Returns the common set of qualifiers while removing them from
/// the given sets.
static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) {
// If both are only CVR-qualified, bit operations are sufficient.
if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) {
Qualifiers Q;
Q.Mask = L.Mask & R.Mask;
L.Mask &= ~Q.Mask;
R.Mask &= ~Q.Mask;
return Q;
}
Qualifiers Q;
unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers();
Q.addCVRQualifiers(CommonCRV);
L.removeCVRQualifiers(CommonCRV);
R.removeCVRQualifiers(CommonCRV);
if (L.getObjCGCAttr() == R.getObjCGCAttr()) {
Q.setObjCGCAttr(L.getObjCGCAttr());
L.removeObjCGCAttr();
R.removeObjCGCAttr();
}
if (L.getObjCLifetime() == R.getObjCLifetime()) {
Q.setObjCLifetime(L.getObjCLifetime());
L.removeObjCLifetime();
R.removeObjCLifetime();
}
if (L.getAddressSpace() == R.getAddressSpace()) {
Q.setAddressSpace(L.getAddressSpace());
L.removeAddressSpace();
R.removeAddressSpace();
}
return Q;
}
static Qualifiers fromFastMask(unsigned Mask) {
Qualifiers Qs;
Qs.addFastQualifiers(Mask);
@ -333,6 +372,23 @@ class Qualifiers {
}
}
/// \brief Remove the qualifiers from the given set from this set.
void removeQualifiers(Qualifiers Q) {
// If the other set doesn't have any non-boolean qualifiers, just
// bit-and the inverse in.
if (!(Q.Mask & ~CVRMask))
Mask &= ~Q.Mask;
else {
Mask &= ~(Q.Mask & CVRMask);
if (getObjCGCAttr() == Q.getObjCGCAttr())
removeObjCGCAttr();
if (getObjCLifetime() == Q.getObjCLifetime())
removeObjCLifetime();
if (getAddressSpace() == Q.getAddressSpace())
removeAddressSpace();
}
}
/// \brief Add the qualifiers from the given set to this set, given that
/// they don't conflict.
void addConsistentQualifiers(Qualifiers qs) {
@ -400,7 +456,7 @@ class Qualifiers {
}
Qualifiers &operator-=(Qualifiers R) {
Mask = Mask & ~(R.Mask);
removeQualifiers(R);
return *this;
}
@ -435,18 +491,6 @@ class Qualifiers {
static const uint32_t AddressSpaceShift = 8;
};
/// CallingConv - Specifies the calling convention that a function uses.
enum CallingConv {
CC_Default,
CC_C, // __attribute__((cdecl))
CC_X86StdCall, // __attribute__((stdcall))
CC_X86FastCall, // __attribute__((fastcall))
CC_X86ThisCall, // __attribute__((thiscall))
CC_X86Pascal, // __attribute__((pascal))
CC_AAPCS, // __attribute__((pcs("aapcs")))
CC_AAPCS_VFP // __attribute__((pcs("aapcs-vfp")))
};
/// A std::pair-like structure for storing a qualified type split
/// into its local qualifiers and its locally-unqualified type.
struct SplitQualType {
@ -1126,8 +1170,8 @@ class Type : public ExtQualsTypeCommonBase {
};
private:
Type(const Type&); // DO NOT IMPLEMENT.
void operator=(const Type&); // DO NOT IMPLEMENT.
Type(const Type &) LLVM_DELETED_FUNCTION;
void operator=(const Type &) LLVM_DELETED_FUNCTION;
/// Bitfields required by the Type class.
class TypeBitfields {
@ -1225,7 +1269,7 @@ class Type : public ExtQualsTypeCommonBase {
/// Extra information which affects how the function is called, like
/// regparm and the calling convention.
unsigned ExtInfo : 8;
unsigned ExtInfo : 9;
/// TypeQuals - Used only by FunctionProtoType, put here to pack with the
/// other bitfields.
@ -1512,6 +1556,7 @@ class Type : public ExtQualsTypeCommonBase {
bool isRecordType() const;
bool isClassType() const;
bool isStructureType() const;
bool isInterfaceType() const;
bool isStructureOrClassType() const;
bool isUnionType() const;
bool isComplexIntegerType() const; // GCC _Complex integer type.
@ -1630,13 +1675,19 @@ class Type : public ExtQualsTypeCommonBase {
const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
const ObjCObjectPointerType *getAsObjCQualifiedClassType() const;
const ObjCObjectType *getAsObjCQualifiedInterfaceType() const;
const CXXRecordDecl *getCXXRecordDeclForPointerType() const;
/// \brief Retrieves the CXXRecordDecl that this type refers to, either
/// because the type is a RecordType or because it is the injected-class-name
/// type of a class template or class template partial specialization.
CXXRecordDecl *getAsCXXRecordDecl() const;
/// If this is a pointer or reference to a RecordType, return the
/// CXXRecordDecl that that type refers to.
///
/// If this is not a pointer or reference, or the type being pointed to does
/// not refer to a CXXRecordDecl, returns NULL.
const CXXRecordDecl *getPointeeCXXRecordDecl() const;
/// \brief Get the AutoType whose type will be deduced for a variable with
/// an initializer of this type. This looks through declarators like pointer
/// types, but not through decltype or typedefs.
@ -1738,8 +1789,6 @@ class Type : public ExtQualsTypeCommonBase {
CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
LLVM_ATTRIBUTE_USED void dump() const;
static bool classof(const Type *) { return true; }
friend class ASTReader;
friend class ASTWriter;
};
@ -1748,6 +1797,11 @@ class Type : public ExtQualsTypeCommonBase {
/// until it reaches a TypedefType or a non-sugared type.
template <> const TypedefType *Type::getAs() const;
/// \brief This will check for a TemplateSpecializationType by removing any
/// existing sugar until it reaches a TemplateSpecializationType or a
/// non-sugared type.
template <> const TemplateSpecializationType *Type::getAs() const;
// We can do canonical leaf types faster, because we don't have to
// worry about preserving child type decoration.
#define TYPE(Class, Base)
@ -1834,7 +1888,6 @@ class BuiltinType : public Type {
}
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
static bool classof(const BuiltinType *) { return true; }
};
/// ComplexType - C99 6.2.5p11 - Complex values. This supports the C99 complex
@ -1865,7 +1918,6 @@ class ComplexType : public Type, public llvm::FoldingSetNode {
}
static bool classof(const Type *T) { return T->getTypeClass() == Complex; }
static bool classof(const ComplexType *) { return true; }
};
/// ParenType - Sugar for parentheses used when specifying types.
@ -1897,7 +1949,6 @@ class ParenType : public Type, public llvm::FoldingSetNode {
}
static bool classof(const Type *T) { return T->getTypeClass() == Paren; }
static bool classof(const ParenType *) { return true; }
};
/// PointerType - C99 6.7.5.1 - Pointer Declarators.
@ -1929,7 +1980,6 @@ class PointerType : public Type, public llvm::FoldingSetNode {
}
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
static bool classof(const PointerType *) { return true; }
};
/// BlockPointerType - pointer to a block type.
@ -1965,7 +2015,6 @@ class BlockPointerType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == BlockPointer;
}
static bool classof(const BlockPointerType *) { return true; }
};
/// ReferenceType - Base for LValueReferenceType and RValueReferenceType
@ -2013,7 +2062,6 @@ class ReferenceType : public Type, public llvm::FoldingSetNode {
return T->getTypeClass() == LValueReference ||
T->getTypeClass() == RValueReference;
}
static bool classof(const ReferenceType *) { return true; }
};
/// LValueReferenceType - C++ [dcl.ref] - Lvalue reference
@ -2031,7 +2079,6 @@ class LValueReferenceType : public ReferenceType {
static bool classof(const Type *T) {
return T->getTypeClass() == LValueReference;
}
static bool classof(const LValueReferenceType *) { return true; }
};
/// RValueReferenceType - C++0x [dcl.ref] - Rvalue reference
@ -2048,7 +2095,6 @@ class RValueReferenceType : public ReferenceType {
static bool classof(const Type *T) {
return T->getTypeClass() == RValueReference;
}
static bool classof(const RValueReferenceType *) { return true; }
};
/// MemberPointerType - C++ 8.3.3 - Pointers to members
@ -2103,7 +2149,6 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == MemberPointer;
}
static bool classof(const MemberPointerType *) { return true; }
};
/// ArrayType - C99 6.7.5.2 - Array Declarators.
@ -2159,7 +2204,6 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
T->getTypeClass() == IncompleteArray ||
T->getTypeClass() == DependentSizedArray;
}
static bool classof(const ArrayType *) { return true; }
};
/// ConstantArrayType - This class represents the canonical version of
@ -2211,7 +2255,6 @@ class ConstantArrayType : public ArrayType {
static bool classof(const Type *T) {
return T->getTypeClass() == ConstantArray;
}
static bool classof(const ConstantArrayType *) { return true; }
};
/// IncompleteArrayType - This class represents C arrays with an unspecified
@ -2231,7 +2274,6 @@ class IncompleteArrayType : public ArrayType {
static bool classof(const Type *T) {
return T->getTypeClass() == IncompleteArray;
}
static bool classof(const IncompleteArrayType *) { return true; }
friend class StmtIteratorBase;
@ -2294,7 +2336,6 @@ class VariableArrayType : public ArrayType {
static bool classof(const Type *T) {
return T->getTypeClass() == VariableArray;
}
static bool classof(const VariableArrayType *) { return true; }
friend class StmtIteratorBase;
@ -2351,7 +2392,6 @@ class DependentSizedArrayType : public ArrayType {
static bool classof(const Type *T) {
return T->getTypeClass() == DependentSizedArray;
}
static bool classof(const DependentSizedArrayType *) { return true; }
friend class StmtIteratorBase;
@ -2397,7 +2437,6 @@ class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == DependentSizedExtVector;
}
static bool classof(const DependentSizedExtVectorType *) { return true; }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, Context, getElementType(), getSizeExpr());
@ -2463,7 +2502,6 @@ class VectorType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector;
}
static bool classof(const VectorType *) { return true; }
};
/// ExtVectorType - Extended vector type. This type is created using
@ -2529,7 +2567,6 @@ class ExtVectorType : public VectorType {
static bool classof(const Type *T) {
return T->getTypeClass() == ExtVector;
}
static bool classof(const ExtVectorType *) { return true; }
};
/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base
@ -2561,19 +2598,19 @@ class FunctionType : public Type {
// * AST read and write
// * Codegen
class ExtInfo {
// Feel free to rearrange or add bits, but if you go over 8,
// Feel free to rearrange or add bits, but if you go over 9,
// you'll need to adjust both the Bits field below and
// Type::FunctionTypeBitfields.
// | CC |noreturn|produces|regparm|
// |0 .. 2| 3 | 4 | 5 .. 7|
// |0 .. 3| 4 | 5 | 6 .. 8|
//
// regparm is either 0 (no regparm attribute) or the regparm value+1.
enum { CallConvMask = 0x7 };
enum { NoReturnMask = 0x8 };
enum { ProducesResultMask = 0x10 };
enum { CallConvMask = 0xF };
enum { NoReturnMask = 0x10 };
enum { ProducesResultMask = 0x20 };
enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask),
RegParmOffset = 5 }; // Assumed to be the last field
RegParmOffset = 6 }; // Assumed to be the last field
uint16_t Bits;
@ -2692,7 +2729,6 @@ class FunctionType : public Type {
return T->getTypeClass() == FunctionNoProto ||
T->getTypeClass() == FunctionProto;
}
static bool classof(const FunctionType *) { return true; }
};
/// FunctionNoProtoType - Represents a K&R-style 'int foo()' function, which has
@ -2724,7 +2760,6 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionNoProto;
}
static bool classof(const FunctionNoProtoType *) { return true; }
};
/// FunctionProtoType - Represents a prototype with argument type info, e.g.
@ -2972,14 +3007,13 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
// FIXME: Remove the string version.
void printExceptionSpecification(std::string &S,
PrintingPolicy Policy) const;
const PrintingPolicy &Policy) const;
void printExceptionSpecification(raw_ostream &OS,
PrintingPolicy Policy) const;
const PrintingPolicy &Policy) const;
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionProto;
}
static bool classof(const FunctionProtoType *) { return true; }
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
@ -3010,7 +3044,6 @@ class UnresolvedUsingType : public Type {
static bool classof(const Type *T) {
return T->getTypeClass() == UnresolvedUsing;
}
static bool classof(const UnresolvedUsingType *) { return true; }
void Profile(llvm::FoldingSetNodeID &ID) {
return Profile(ID, Decl);
@ -3042,7 +3075,6 @@ class TypedefType : public Type {
QualType desugar() const;
static bool classof(const Type *T) { return T->getTypeClass() == Typedef; }
static bool classof(const TypedefType *) { return true; }
};
/// TypeOfExprType (GCC extension).
@ -3062,7 +3094,6 @@ class TypeOfExprType : public Type {
bool isSugared() const;
static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; }
static bool classof(const TypeOfExprType *) { return true; }
};
/// \brief Internal representation of canonical, dependent
@ -3109,7 +3140,6 @@ class TypeOfType : public Type {
bool isSugared() const { return true; }
static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; }
static bool classof(const TypeOfType *) { return true; }
};
/// DecltypeType (C++0x)
@ -3131,7 +3161,6 @@ class DecltypeType : public Type {
bool isSugared() const;
static bool classof(const Type *T) { return T->getTypeClass() == Decltype; }
static bool classof(const DecltypeType *) { return true; }
};
/// \brief Internal representation of canonical, dependent
@ -3184,7 +3213,6 @@ class UnaryTransformType : public Type {
static bool classof(const Type *T) {
return T->getTypeClass() == UnaryTransform;
}
static bool classof(const UnaryTransformType *) { return true; }
};
class TagType : public Type {
@ -3207,7 +3235,6 @@ class TagType : public Type {
static bool classof(const Type *T) {
return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
}
static bool classof(const TagType *) { return true; }
};
/// RecordType - This is a helper class that allows the use of isa/cast/dyncast
@ -3234,7 +3261,6 @@ class RecordType : public TagType {
QualType desugar() const { return QualType(this, 0); }
static bool classof(const Type *T) { return T->getTypeClass() == Record; }
static bool classof(const RecordType *) { return true; }
};
/// EnumType - This is a helper class that allows the use of isa/cast/dyncast
@ -3253,7 +3279,6 @@ class EnumType : public TagType {
QualType desugar() const { return QualType(this, 0); }
static bool classof(const Type *T) { return T->getTypeClass() == Enum; }
static bool classof(const EnumType *) { return true; }
};
/// AttributedType - An attributed type is a type to which a type
@ -3297,7 +3322,8 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
attr_fastcall,
attr_stdcall,
attr_thiscall,
attr_pascal
attr_pascal,
attr_pnaclcall
};
private:
@ -3341,7 +3367,6 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == Attributed;
}
static bool classof(const AttributedType *T) { return true; }
};
class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
@ -3415,7 +3440,6 @@ class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == TemplateTypeParm;
}
static bool classof(const TemplateTypeParmType *T) { return true; }
};
/// \brief Represents the result of substituting a type for a template
@ -3466,7 +3490,6 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == SubstTemplateTypeParm;
}
static bool classof(const SubstTemplateTypeParmType *T) { return true; }
};
/// \brief Represents the result of substituting a set of types for a template
@ -3519,7 +3542,6 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == SubstTemplateTypeParmPack;
}
static bool classof(const SubstTemplateTypeParmPackType *T) { return true; }
};
/// \brief Represents a C++0x auto type.
@ -3562,7 +3584,6 @@ class AutoType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == Auto;
}
static bool classof(const AutoType *T) { return true; }
};
/// \brief Represents a type template specialization; the template
@ -3726,7 +3747,6 @@ class TemplateSpecializationType
static bool classof(const Type *T) {
return T->getTypeClass() == TemplateSpecialization;
}
static bool classof(const TemplateSpecializationType *T) { return true; }
};
/// \brief The injected class name of a C++ class template or class
@ -3789,13 +3809,14 @@ class InjectedClassNameType : public Type {
static bool classof(const Type *T) {
return T->getTypeClass() == InjectedClassName;
}
static bool classof(const InjectedClassNameType *T) { return true; }
};
/// \brief The kind of a tag type.
enum TagTypeKind {
/// \brief The "struct" keyword.
TTK_Struct,
/// \brief The "__interface" keyword.
TTK_Interface,
/// \brief The "union" keyword.
TTK_Union,
/// \brief The "class" keyword.
@ -3809,6 +3830,8 @@ enum TagTypeKind {
enum ElaboratedTypeKeyword {
/// \brief The "struct" keyword introduces the elaborated-type-specifier.
ETK_Struct,
/// \brief The "__interface" keyword introduces the elaborated-type-specifier.
ETK_Interface,
/// \brief The "union" keyword introduces the elaborated-type-specifier.
ETK_Union,
/// \brief The "class" keyword introduces the elaborated-type-specifier.
@ -3932,7 +3955,6 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == Elaborated;
}
static bool classof(const ElaboratedType *T) { return true; }
};
/// \brief Represents a qualified type name for which the type name is
@ -3996,7 +4018,6 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == DependentName;
}
static bool classof(const DependentNameType *T) { return true; }
};
/// DependentTemplateSpecializationType - Represents a template
@ -4067,9 +4088,6 @@ class DependentTemplateSpecializationType :
static bool classof(const Type *T) {
return T->getTypeClass() == DependentTemplateSpecialization;
}
static bool classof(const DependentTemplateSpecializationType *T) {
return true;
}
};
/// \brief Represents a pack expansion of types.
@ -4150,9 +4168,6 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == PackExpansion;
}
static bool classof(const PackExpansionType *T) {
return true;
}
};
/// ObjCObjectType - Represents a class type in Objective C.
@ -4263,7 +4278,6 @@ class ObjCObjectType : public Type {
return T->getTypeClass() == ObjCObject ||
T->getTypeClass() == ObjCInterface;
}
static bool classof(const ObjCObjectType *) { return true; }
};
/// ObjCObjectTypeImpl - A class providing a concrete implementation
@ -4327,7 +4341,6 @@ class ObjCInterfaceType : public ObjCObjectType {
static bool classof(const Type *T) {
return T->getTypeClass() == ObjCInterface;
}
static bool classof(const ObjCInterfaceType *) { return true; }
// Nonsense to "hide" certain members of ObjCObjectType within this
// class. People asking for protocols on an ObjCInterfaceType are
@ -4477,7 +4490,6 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == ObjCObjectPointer;
}
static bool classof(const ObjCObjectPointerType *) { return true; }
};
class AtomicType : public Type, public llvm::FoldingSetNode {
@ -4508,7 +4520,6 @@ class AtomicType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == Atomic;
}
static bool classof(const AtomicType *) { return true; }
};
/// A qualifier set is used to build a set of qualifiers.

View File

@ -159,8 +159,6 @@ class TypeLoc {
return !(LHS == RHS);
}
static bool classof(const TypeLoc *TL) { return true; }
private:
static void initializeImpl(ASTContext &Context, TypeLoc TL,
SourceLocation Loc);
@ -192,7 +190,6 @@ class UnqualTypeLoc : public TypeLoc {
static bool classof(const TypeLoc *TL) {
return !TL->getType().hasLocalQualifiers();
}
static bool classof(const UnqualTypeLoc *TL) { return true; }
};
/// \brief Wrapper of type source information for a type with
@ -237,7 +234,6 @@ class QualifiedTypeLoc : public TypeLoc {
static bool classof(const TypeLoc *TL) {
return TL->getType().hasLocalQualifiers();
}
static bool classof(const QualifiedTypeLoc *TL) { return true; }
};
inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const {
@ -250,11 +246,11 @@ inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const {
/// to a particular Type subclass. It is accepted for a single
/// TypeLoc class to correspond to multiple Type classes.
///
/// \param Base a class from which to derive
/// \param Derived the class deriving from this one
/// \param TypeClass the concrete Type subclass associated with this
/// \tparam Base a class from which to derive
/// \tparam Derived the class deriving from this one
/// \tparam TypeClass the concrete Type subclass associated with this
/// location type
/// \param LocalData the structure type of local location data for
/// \tparam LocalData the structure type of local location data for
/// this type
///
/// sizeof(LocalData) needs to be a multiple of sizeof(void*) or
@ -303,9 +299,6 @@ class ConcreteTypeLoc : public Base {
static bool classof(const UnqualTypeLoc *TL) {
return Derived::classofType(TL->getTypePtr());
}
static bool classof(const Derived *TL) {
return true;
}
TypeLoc getNextTypeLoc() const {
return getNextTypeLoc(asDerived()->getInnerType());
@ -380,9 +373,6 @@ class InheritingConcreteTypeLoc : public Base {
static bool classof(const UnqualTypeLoc *TL) {
return Derived::classofType(TL->getTypePtr());
}
static bool classof(const Derived *TL) {
return true;
}
const TypeClass *getTypePtr() const {
return cast<TypeClass>(Base::getTypePtr());
@ -417,7 +407,6 @@ class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
}
static bool classof(const TypeLoc *TL);
static bool classof(const TypeSpecTypeLoc *TL) { return true; }
};
@ -866,6 +855,7 @@ class ObjCInterfaceTypeLoc : public ConcreteTypeLoc<ObjCObjectTypeLoc,
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setNameLoc(Loc);
setNameEndLoc(Loc);
}
};
@ -1060,6 +1050,8 @@ class RValueReferenceTypeLoc :
struct FunctionLocInfo {
SourceLocation LocalRangeBegin;
SourceLocation LParenLoc;
SourceLocation RParenLoc;
SourceLocation LocalRangeEnd;
};
@ -1083,6 +1075,24 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
getLocalData()->LocalRangeEnd = L;
}
SourceLocation getLParenLoc() const {
return this->getLocalData()->LParenLoc;
}
void setLParenLoc(SourceLocation Loc) {
this->getLocalData()->LParenLoc = Loc;
}
SourceLocation getRParenLoc() const {
return this->getLocalData()->RParenLoc;
}
void setRParenLoc(SourceLocation Loc) {
this->getLocalData()->RParenLoc = Loc;
}
SourceRange getParensRange() const {
return SourceRange(getLParenLoc(), getRParenLoc());
}
ArrayRef<ParmVarDecl *> getParams() const {
return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs());
}
@ -1110,6 +1120,8 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setLocalRangeBegin(Loc);
setLParenLoc(Loc);
setRParenLoc(Loc);
setLocalRangeEnd(Loc);
for (unsigned i = 0, e = getNumArgs(); i != e; ++i)
setArg(i, NULL);

View File

@ -94,7 +94,7 @@ class UnresolvedSetImpl {
private:
template <unsigned N> friend class UnresolvedSet;
UnresolvedSetImpl() {}
UnresolvedSetImpl(const UnresolvedSetImpl &) {}
UnresolvedSetImpl(const UnresolvedSetImpl &) LLVM_DELETED_FUNCTION;
public:
// We don't currently support assignment through this iterator, so we might

View File

@ -147,9 +147,10 @@ class VTableComponent {
assert((ComponentKind == CK_VCallOffset ||
ComponentKind == CK_VBaseOffset ||
ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!");
assert(Offset.getQuantity() < (1LL << 56) && "Offset is too big!");
assert(Offset.getQuantity() >= -(1LL << 56) && "Offset is too small!");
Value = ((Offset.getQuantity() << 3) | ComponentKind);
Value = (uint64_t(Offset.getQuantity()) << 3) | ComponentKind;
}
VTableComponent(Kind ComponentKind, uintptr_t Ptr) {

View File

@ -85,7 +85,14 @@ class MatchFinder {
class MatchCallback {
public:
virtual ~MatchCallback();
/// \brief Called on every match by the \c MatchFinder.
virtual void run(const MatchResult &Result) = 0;
/// \brief Called at the start of each translation unit.
///
/// Optionally override to do per translation unit tasks.
virtual void onStartOfTranslationUnit() {}
};
/// \brief Called when parsing is finished. Intended for testing only.
@ -112,11 +119,24 @@ class MatchFinder {
MatchCallback *Action);
void addMatcher(const StatementMatcher &NodeMatch,
MatchCallback *Action);
void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
MatchCallback *Action);
void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
MatchCallback *Action);
void addMatcher(const TypeLocMatcher &NodeMatch,
MatchCallback *Action);
/// @}
/// \brief Creates a clang ASTConsumer that finds all matches.
clang::ASTConsumer *newASTConsumer();
/// \brief Finds all matches on the given \c Node.
///
/// @{
void findAll(const Decl &Node, ASTContext &Context);
void findAll(const Stmt &Node, ASTContext &Context);
/// @}
/// \brief Registers a callback to notify the end of parsing.
///
/// The provided closure is called after parsing is done, before the AST is
@ -125,11 +145,10 @@ class MatchFinder {
void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
private:
/// \brief The MatchCallback*'s will be called every time the
/// UntypedBaseMatcher matches on the AST.
std::vector< std::pair<
const internal::UntypedBaseMatcher*,
MatchCallback*> > Triggers;
/// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called
/// when it matches.
std::vector<std::pair<const internal::DynTypedMatcher*, MatchCallback*> >
MatcherCallbackPairs;
/// \brief Called when parsing is done.
ParsingDoneTestCallback *ParsingDone;

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,11 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/Type.h"
#include "clang/ASTMatchers/ASTTypeTraits.h"
#include "llvm/ADT/VariadicFunction.h"
#include "llvm/Support/type_traits.h"
#include <map>
#include <string>
#include <vector>
@ -57,6 +61,45 @@ class BoundNodes;
namespace internal {
class BoundNodesTreeBuilder;
/// \brief Internal version of BoundNodes. Holds all the bound nodes.
class BoundNodesMap {
public:
/// \brief Adds \c Node to the map with key \c ID.
///
/// The node's base type should be in NodeBaseType or it will be unaccessible.
template <typename T>
void addNode(StringRef ID, const T* Node) {
NodeMap[ID] = ast_type_traits::DynTypedNode::create(*Node);
}
void addNode(StringRef ID, ast_type_traits::DynTypedNode Node) {
NodeMap[ID] = Node;
}
/// \brief Returns the AST node bound to \c ID.
///
/// Returns NULL if there was no node bound to \c ID or if there is a node but
/// it cannot be converted to the specified type.
template <typename T>
const T *getNodeAs(StringRef ID) const {
IDToNodeMap::const_iterator It = NodeMap.find(ID);
if (It == NodeMap.end()) {
return NULL;
}
return It->second.get<T>();
}
/// \brief Copies all ID/Node pairs to BoundNodesTreeBuilder \c Builder.
void copyTo(BoundNodesTreeBuilder *Builder) const;
/// \brief Copies all ID/Node pairs to BoundNodesMap \c Other.
void copyTo(BoundNodesMap *Other) const;
private:
/// \brief A map from IDs to the bound nodes.
typedef std::map<std::string, ast_type_traits::DynTypedNode> IDToNodeMap;
IDToNodeMap NodeMap;
};
/// \brief A tree of bound nodes in match results.
///
@ -84,11 +127,10 @@ class BoundNodesTree {
BoundNodesTree();
/// \brief Create a BoundNodesTree from pre-filled maps of bindings.
BoundNodesTree(const std::map<std::string, const Decl*>& DeclBindings,
const std::map<std::string, const Stmt*>& StmtBindings,
BoundNodesTree(const BoundNodesMap& Bindings,
const std::vector<BoundNodesTree> RecursiveBindings);
/// \brief Adds all bound nodes to bound_nodes_builder.
/// \brief Adds all bound nodes to \c Builder.
void copyTo(BoundNodesTreeBuilder* Builder) const;
/// \brief Visits all matches that this BoundNodesTree represents.
@ -99,17 +141,12 @@ class BoundNodesTree {
private:
void visitMatchesRecursively(
Visitor* ResultVistior,
std::map<std::string, const Decl*> DeclBindings,
std::map<std::string, const Stmt*> StmtBindings);
template <typename T>
void copyBindingsTo(const T& bindings, BoundNodesTreeBuilder* Builder) const;
const BoundNodesMap& AggregatedBindings);
// FIXME: Find out whether we want to use different data structures here -
// first benchmarks indicate that it doesn't matter though.
std::map<std::string, const Decl*> DeclBindings;
std::map<std::string, const Stmt*> StmtBindings;
BoundNodesMap Bindings;
std::vector<BoundNodesTree> RecursiveBindings;
};
@ -123,12 +160,13 @@ class BoundNodesTreeBuilder {
BoundNodesTreeBuilder();
/// \brief Add a binding from an id to a node.
///
/// FIXME: Add overloads for all AST base types.
/// @{
void setBinding(const std::string &Id, const Decl *Node);
void setBinding(const std::string &Id, const Stmt *Node);
/// @}
template <typename T>
void setBinding(const std::string &Id, const T *Node) {
Bindings.addNode(Id, Node);
}
void setBinding(const std::string &Id, ast_type_traits::DynTypedNode Node) {
Bindings.addNode(Id, Node);
}
/// \brief Adds a branch in the tree.
void addMatch(const BoundNodesTree& Bindings);
@ -137,11 +175,10 @@ class BoundNodesTreeBuilder {
BoundNodesTree build() const;
private:
BoundNodesTreeBuilder(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
void operator=(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
BoundNodesTreeBuilder(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION;
void operator=(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION;
std::map<std::string, const Decl*> DeclBindings;
std::map<std::string, const Stmt*> StmtBindings;
BoundNodesMap Bindings;
std::vector<BoundNodesTree> RecursiveBindings;
};
@ -169,7 +206,8 @@ class MatcherInterface : public llvm::RefCountedBaseVPTR {
BoundNodesTreeBuilder *Builder) const = 0;
};
/// \brief Interface for matchers that only evaluate properties on a single node.
/// \brief Interface for matchers that only evaluate properties on a single
/// node.
template <typename T>
class SingleNodeMatcherInterface : public MatcherInterface<T> {
public:
@ -187,6 +225,24 @@ class SingleNodeMatcherInterface : public MatcherInterface<T> {
}
};
/// \brief Base class for all matchers that works on a \c DynTypedNode.
///
/// Matcher implementations will check whether the \c DynTypedNode is
/// convertible into the respecitve types and then do the actual match
/// on the actual node, or return false if it is not convertible.
class DynTypedMatcher {
public:
virtual ~DynTypedMatcher() {}
/// \brief Returns true if the matcher matches the given \c DynNode.
virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const = 0;
/// \brief Returns a unique ID for the matcher.
virtual uint64_t getID() const = 0;
};
/// \brief Wrapper of a MatcherInterface<T> *that allows copying.
///
/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
@ -196,12 +252,32 @@ class SingleNodeMatcherInterface : public MatcherInterface<T> {
/// operator rather than a type hierarchy to be able to templatize the
/// type hierarchy instead of spelling it out.
template <typename T>
class Matcher {
class Matcher : public DynTypedMatcher {
public:
/// \brief Takes ownership of the provided implementation pointer.
explicit Matcher(MatcherInterface<T> *Implementation)
: Implementation(Implementation) {}
/// \brief Implicitly converts \c Other to a Matcher<T>.
///
/// Requires \c T to be derived from \c From.
template <typename From>
Matcher(const Matcher<From> &Other,
typename llvm::enable_if_c<
llvm::is_base_of<From, T>::value &&
!llvm::is_same<From, T>::value >::type* = 0)
: Implementation(new ImplicitCastMatcher<From>(Other)) {}
/// \brief Implicitly converts \c Matcher<Type> to \c Matcher<QualType>.
///
/// The resulting matcher is not strict, i.e. ignores qualifiers.
template <typename TypeT>
Matcher(const Matcher<TypeT> &Other,
typename llvm::enable_if_c<
llvm::is_same<T, QualType>::value &&
llvm::is_same<TypeT, Type>::value >::type* = 0)
: Implementation(new TypeToQualType<TypeT>(Other)) {}
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
bool matches(const T &Node,
ASTMatchFinder *Finder,
@ -209,14 +285,6 @@ class Matcher {
return Implementation->matches(Node, Finder, Builder);
}
/// \brief Implicitly converts this object to a Matcher<Derived>.
///
/// Requires Derived to be derived from T.
template <typename Derived>
operator Matcher<Derived>() const {
return Matcher<Derived>(new ImplicitCastMatcher<Derived>(*this));
}
/// \brief Returns an ID that uniquely identifies the matcher.
uint64_t getID() const {
/// FIXME: Document the requirements this imposes on matcher
@ -224,23 +292,55 @@ class Matcher {
return reinterpret_cast<uint64_t>(Implementation.getPtr());
}
/// \brief Returns whether the matcher matches on the given \c DynNode.
virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
const T *Node = DynNode.get<T>();
if (!Node) return false;
return matches(*Node, Finder, Builder);
}
/// \brief Allows the conversion of a \c Matcher<Type> to a \c
/// Matcher<QualType>.
///
/// Depending on the constructor argument, the matcher is either strict, i.e.
/// does only matches in the absence of qualifiers, or not, i.e. simply
/// ignores any qualifiers.
template <typename TypeT>
class TypeToQualType : public MatcherInterface<QualType> {
public:
TypeToQualType(const Matcher<TypeT> &InnerMatcher)
: InnerMatcher(InnerMatcher) {}
virtual bool matches(const QualType &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
if (Node.isNull())
return false;
return InnerMatcher.matches(*Node, Finder, Builder);
}
private:
const Matcher<TypeT> InnerMatcher;
};
private:
/// \brief Allows conversion from Matcher<T> to Matcher<Derived> if Derived
/// is derived from T.
template <typename Derived>
class ImplicitCastMatcher : public MatcherInterface<Derived> {
/// \brief Allows conversion from Matcher<Base> to Matcher<T> if T
/// is derived from Base.
template <typename Base>
class ImplicitCastMatcher : public MatcherInterface<T> {
public:
explicit ImplicitCastMatcher(const Matcher<T> &From)
explicit ImplicitCastMatcher(const Matcher<Base> &From)
: From(From) {}
virtual bool matches(const Derived &Node,
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return From.matches(Node, Finder, Builder);
}
private:
const Matcher<T> From;
const Matcher<Base> From;
};
llvm::IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
@ -280,18 +380,14 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
/// FIXME: Add other ways to convert...
if (Node.isNull())
return false;
CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl();
return NodeAsRecordDecl != NULL &&
InnerMatcher.matches(*NodeAsRecordDecl, Finder, Builder);
return matchesDecl(Node->getAsCXXRecordDecl(), Finder, Builder);
}
/// \brief Extracts the Decl of the callee of a CallExpr and returns whether
/// the inner matcher matches on it.
bool matchesSpecialized(const CallExpr &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
const Decl *NodeAsDecl = Node.getCalleeDecl();
return NodeAsDecl != NULL &&
InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
return matchesDecl(Node.getCalleeDecl(), Finder, Builder);
}
/// \brief Extracts the Decl of the constructor call and returns whether the
@ -299,96 +395,63 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
bool matchesSpecialized(const CXXConstructExpr &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
const Decl *NodeAsDecl = Node.getConstructor();
return NodeAsDecl != NULL &&
InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
return matchesDecl(Node.getConstructor(), Finder, Builder);
}
/// \brief Extracts the \c ValueDecl a \c MemberExpr refers to and returns
/// whether the inner matcher matches on it.
bool matchesSpecialized(const MemberExpr &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return matchesDecl(Node.getMemberDecl(), Finder, Builder);
}
/// \brief Returns whether the inner matcher \c Node. Returns false if \c Node
/// is \c NULL.
bool matchesDecl(const Decl *Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return Node != NULL && InnerMatcher.matches(*Node, Finder, Builder);
}
const Matcher<Decl> InnerMatcher;
};
/// \brief IsBaseType<T>::value is true if T is a "base" type in the AST
/// node class hierarchies (i.e. if T is Decl, Stmt, or QualType).
/// node class hierarchies.
template <typename T>
struct IsBaseType {
static const bool value =
(llvm::is_same<T, Decl>::value ||
llvm::is_same<T, Stmt>::value ||
llvm::is_same<T, QualType>::value ||
llvm::is_same<T, Type>::value ||
llvm::is_same<T, TypeLoc>::value ||
llvm::is_same<T, NestedNameSpecifier>::value ||
llvm::is_same<T, NestedNameSpecifierLoc>::value ||
llvm::is_same<T, CXXCtorInitializer>::value);
};
template <typename T>
const bool IsBaseType<T>::value;
/// \brief Interface that can match any AST base node type and contains default
/// implementations returning false.
class UntypedBaseMatcher : public llvm::RefCountedBaseVPTR {
public:
virtual ~UntypedBaseMatcher() {}
virtual bool matches(const Decl &DeclNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return false;
}
virtual bool matches(const QualType &TypeNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return false;
}
virtual bool matches(const Stmt &StmtNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return false;
}
virtual bool matches(const CXXCtorInitializer &CtorInitNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return false;
}
/// \brief Returns a unique ID for the matcher.
virtual uint64_t getID() const = 0;
};
/// \brief An UntypedBaseMatcher that overwrites the Matches(...) method for
/// node type T. T must be an AST base type.
template <typename T>
class TypedBaseMatcher : public UntypedBaseMatcher {
TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
typed_base_matcher_can_only_be_used_with_base_type);
public:
explicit TypedBaseMatcher(const Matcher<T> &InnerMatcher)
: InnerMatcher(InnerMatcher) {}
using UntypedBaseMatcher::matches;
/// \brief Implements UntypedBaseMatcher::Matches.
///
/// Since T is guaranteed to be a "base" AST node type, this method is
/// guaranteed to override one of the matches() methods from
/// UntypedBaseMatcher.
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return InnerMatcher.matches(Node, Finder, Builder);
}
/// \brief Implements UntypedBaseMatcher::getID.
virtual uint64_t getID() const {
return InnerMatcher.getID();
}
private:
Matcher<T> InnerMatcher;
};
/// \brief Interface that allows matchers to traverse the AST.
/// FIXME: Find a better name.
///
/// This provides two entry methods for each base node type in the AST:
/// - matchesChildOf:
/// This provides three entry methods for each base node type in the AST:
/// - \c matchesChildOf:
/// Matches a matcher on every child node of the given node. Returns true
/// if at least one child node could be matched.
/// - matchesDescendantOf:
/// - \c matchesDescendantOf:
/// Matches a matcher on all descendant nodes of the given node. Returns true
/// if at least one descendant matched.
/// - \c matchesAncestorOf:
/// Matches a matcher on all ancestors of the given node. Returns true if
/// at least one ancestor matched.
///
/// FIXME: Currently we only allow Stmt and Decl nodes to start a traversal.
/// In the future, we wan to implement this for all nodes for which it makes
/// sense. In the case of matchesAncestorOf, we'll want to implement it for
/// all nodes, as all nodes have ancestors.
class ASTMatchFinder {
public:
/// \brief Defines how we descend a level in the AST when we pass
@ -408,6 +471,14 @@ class ASTMatchFinder {
BK_All
};
/// \brief Defines which ancestors are considered for a match.
enum AncestorMatchMode {
/// All ancestors.
AMM_All,
/// Direct parent only.
AMM_ParentOnly
};
virtual ~ASTMatchFinder() {}
/// \brief Returns true if the given class is directly or indirectly derived
@ -418,26 +489,70 @@ class ASTMatchFinder {
const Matcher<NamedDecl> &Base,
BoundNodesTreeBuilder *Builder) = 0;
// FIXME: Implement for other base nodes.
virtual bool matchesChildOf(const Decl &DeclNode,
const UntypedBaseMatcher &BaseMatcher,
BoundNodesTreeBuilder *Builder,
TraversalKind Traverse,
BindKind Bind) = 0;
virtual bool matchesChildOf(const Stmt &StmtNode,
const UntypedBaseMatcher &BaseMatcher,
template <typename T>
bool matchesChildOf(const T &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
TraversalKind Traverse,
BindKind Bind) {
TOOLING_COMPILE_ASSERT(
(llvm::is_base_of<Decl, T>::value ||
llvm::is_base_of<Stmt, T>::value ||
llvm::is_base_of<NestedNameSpecifier, T>::value ||
llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
llvm::is_base_of<TypeLoc, T>::value ||
llvm::is_base_of<QualType, T>::value),
unsupported_type_for_recursive_matching);
return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
Matcher, Builder, Traverse, Bind);
}
template <typename T>
bool matchesDescendantOf(const T &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
BindKind Bind) {
TOOLING_COMPILE_ASSERT(
(llvm::is_base_of<Decl, T>::value ||
llvm::is_base_of<Stmt, T>::value ||
llvm::is_base_of<NestedNameSpecifier, T>::value ||
llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
llvm::is_base_of<TypeLoc, T>::value ||
llvm::is_base_of<QualType, T>::value),
unsupported_type_for_recursive_matching);
return matchesDescendantOf(ast_type_traits::DynTypedNode::create(Node),
Matcher, Builder, Bind);
}
// FIXME: Implement support for BindKind.
template <typename T>
bool matchesAncestorOf(const T &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) {
TOOLING_COMPILE_ASSERT((llvm::is_base_of<Decl, T>::value ||
llvm::is_base_of<Stmt, T>::value),
only_Decl_or_Stmt_allowed_for_recursive_matching);
return matchesAncestorOf(ast_type_traits::DynTypedNode::create(Node),
Matcher, Builder, MatchMode);
}
protected:
virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
TraversalKind Traverse,
BindKind Bind) = 0;
virtual bool matchesDescendantOf(const Decl &DeclNode,
const UntypedBaseMatcher &BaseMatcher,
BoundNodesTreeBuilder *Builder,
BindKind Bind) = 0;
virtual bool matchesDescendantOf(const Stmt &StmtNode,
const UntypedBaseMatcher &BaseMatcher,
virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
BindKind Bind) = 0;
virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) = 0;
};
/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by
@ -606,9 +721,6 @@ class BindableMatcher : public Matcher<T> {
/// The returned matcher is equivalent to this matcher, but will
/// bind the matched node on a match.
Matcher<T> bind(StringRef ID) const {
TOOLING_COMPILE_ASSERT((llvm::is_base_of<Stmt, T>::value ||
llvm::is_base_of<Decl, T>::value),
trying_to_bind_unsupported_node_type__only_decl_and_stmt_supported);
return Matcher<T>(new IdMatcher<T>(ID, *this));
}
};
@ -635,7 +747,7 @@ class HasMatcher : public MatcherInterface<T> {
}
private:
const TypedBaseMatcher<ChildT> ChildMatcher;
const Matcher<ChildT> ChildMatcher;
};
/// \brief Matches nodes of type T that have child nodes of type ChildT for
@ -661,7 +773,7 @@ class ForEachMatcher : public MatcherInterface<T> {
}
private:
const TypedBaseMatcher<ChildT> ChildMatcher;
const Matcher<ChildT> ChildMatcher;
};
/// \brief Matches nodes of type T if the given Matcher<T> does not match.
@ -733,6 +845,20 @@ class AnyOfMatcher : public MatcherInterface<T> {
const Matcher<T> InnertMatcher2;
};
/// \brief Creates a Matcher<T> that matches if all inner matchers match.
template<typename T>
BindableMatcher<T> makeAllOfComposite(
ArrayRef<const Matcher<T> *> InnerMatchers) {
if (InnerMatchers.empty())
return BindableMatcher<T>(new TrueMatcher<T>);
MatcherInterface<T> *InnerMatcher = new TrueMatcher<T>;
for (int i = InnerMatchers.size() - 1; i >= 0; --i) {
InnerMatcher = new AllOfMatcher<T, Matcher<T>, Matcher<T> >(
*InnerMatchers[i], makeMatcher(InnerMatcher));
}
return BindableMatcher<T>(InnerMatcher);
}
/// \brief Creates a Matcher<T> that matches if
/// T is dyn_cast'able into InnerT and all inner matchers match.
///
@ -742,17 +868,8 @@ class AnyOfMatcher : public MatcherInterface<T> {
template<typename T, typename InnerT>
BindableMatcher<T> makeDynCastAllOfComposite(
ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
if (InnerMatchers.empty()) {
Matcher<InnerT> InnerMatcher = makeMatcher(new TrueMatcher<InnerT>);
return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
}
Matcher<InnerT> InnerMatcher = *InnerMatchers.back();
for (int i = InnerMatchers.size() - 2; i >= 0; --i) {
InnerMatcher = makeMatcher(
new AllOfMatcher<InnerT, Matcher<InnerT>, Matcher<InnerT> >(
*InnerMatchers[i], InnerMatcher));
}
return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(
makeAllOfComposite(InnerMatchers)));
}
/// \brief Matches nodes of type T that have at least one descendant node of
@ -775,7 +892,53 @@ class HasDescendantMatcher : public MatcherInterface<T> {
}
private:
const TypedBaseMatcher<DescendantT> DescendantMatcher;
const Matcher<DescendantT> DescendantMatcher;
};
/// \brief Matches nodes of type \c T that have a parent node of type \c ParentT
/// for which the given inner matcher matches.
///
/// \c ParentT must be an AST base type.
template <typename T, typename ParentT>
class HasParentMatcher : public MatcherInterface<T> {
TOOLING_COMPILE_ASSERT(IsBaseType<ParentT>::value,
has_parent_only_accepts_base_type_matcher);
public:
explicit HasParentMatcher(const Matcher<ParentT> &ParentMatcher)
: ParentMatcher(ParentMatcher) {}
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return Finder->matchesAncestorOf(
Node, ParentMatcher, Builder, ASTMatchFinder::AMM_ParentOnly);
}
private:
const Matcher<ParentT> ParentMatcher;
};
/// \brief Matches nodes of type \c T that have at least one ancestor node of
/// type \c AncestorT for which the given inner matcher matches.
///
/// \c AncestorT must be an AST base type.
template <typename T, typename AncestorT>
class HasAncestorMatcher : public MatcherInterface<T> {
TOOLING_COMPILE_ASSERT(IsBaseType<AncestorT>::value,
has_ancestor_only_accepts_base_type_matcher);
public:
explicit HasAncestorMatcher(const Matcher<AncestorT> &AncestorMatcher)
: AncestorMatcher(AncestorMatcher) {}
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return Finder->matchesAncestorOf(
Node, AncestorMatcher, Builder, ASTMatchFinder::AMM_All);
}
private:
const Matcher<AncestorT> AncestorMatcher;
};
/// \brief Matches nodes of type T that have at least one descendant node of
@ -801,7 +964,7 @@ class ForEachDescendantMatcher : public MatcherInterface<T> {
}
private:
const TypedBaseMatcher<DescendantT> DescendantMatcher;
const Matcher<DescendantT> DescendantMatcher;
};
/// \brief Matches on nodes that have a getValue() method if getValue() equals
@ -858,6 +1021,22 @@ class IsTemplateInstantiationMatcher : public MatcherInterface<T> {
}
};
/// \brief Matches on explicit template specializations for FunctionDecl,
/// VarDecl or CXXRecordDecl nodes.
template <typename T>
class IsExplicitTemplateSpecializationMatcher : public MatcherInterface<T> {
TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, T>::value) ||
(llvm::is_base_of<VarDecl, T>::value) ||
(llvm::is_base_of<CXXRecordDecl, T>::value),
requires_getTemplateSpecializationKind_method);
public:
virtual bool matches(const T& Node,
ASTMatchFinder* Finder,
BoundNodesTreeBuilder* Builder) const {
return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization);
}
};
class IsArrowMatcher : public SingleNodeMatcherInterface<MemberExpr> {
public:
virtual bool matchesNode(const MemberExpr &Node) const {
@ -894,6 +1073,166 @@ class VariadicDynCastAllOfMatcher
VariadicDynCastAllOfMatcher() {}
};
/// \brief A \c VariadicAllOfMatcher<T> object is a variadic functor that takes
/// a number of \c Matcher<T> and returns a \c Matcher<T> that matches \c T
/// nodes that are matched by all of the given matchers.
///
/// For example:
/// const VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier;
/// Creates a functor nestedNameSpecifier(...) that creates a
/// \c Matcher<NestedNameSpecifier> given a variable number of arguments of type
/// \c Matcher<NestedNameSpecifier>.
/// The returned matcher matches if all given matchers match.
template <typename T>
class VariadicAllOfMatcher : public llvm::VariadicFunction<
BindableMatcher<T>, Matcher<T>,
makeAllOfComposite<T> > {
public:
VariadicAllOfMatcher() {}
};
/// \brief Matches nodes of type \c TLoc for which the inner
/// \c Matcher<T> matches.
template <typename TLoc, typename T>
class LocMatcher : public MatcherInterface<TLoc> {
public:
explicit LocMatcher(const Matcher<T> &InnerMatcher)
: InnerMatcher(InnerMatcher) {}
virtual bool matches(const TLoc &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
if (!Node)
return false;
return InnerMatcher.matches(*extract(Node), Finder, Builder);
}
private:
const NestedNameSpecifier *extract(const NestedNameSpecifierLoc &Loc) const {
return Loc.getNestedNameSpecifier();
}
const Matcher<T> InnerMatcher;
};
/// \brief Matches \c NestedNameSpecifiers with a prefix matching another
/// \c Matcher<NestedNameSpecifier>.
class NestedNameSpecifierPrefixMatcher
: public MatcherInterface<NestedNameSpecifier> {
public:
explicit NestedNameSpecifierPrefixMatcher(
const Matcher<NestedNameSpecifier> &InnerMatcher)
: InnerMatcher(InnerMatcher) {}
virtual bool matches(const NestedNameSpecifier &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
NestedNameSpecifier *NextNode = Node.getPrefix();
if (NextNode == NULL)
return false;
return InnerMatcher.matches(*NextNode, Finder, Builder);
}
private:
const Matcher<NestedNameSpecifier> InnerMatcher;
};
/// \brief Matches \c NestedNameSpecifierLocs with a prefix matching another
/// \c Matcher<NestedNameSpecifierLoc>.
class NestedNameSpecifierLocPrefixMatcher
: public MatcherInterface<NestedNameSpecifierLoc> {
public:
explicit NestedNameSpecifierLocPrefixMatcher(
const Matcher<NestedNameSpecifierLoc> &InnerMatcher)
: InnerMatcher(InnerMatcher) {}
virtual bool matches(const NestedNameSpecifierLoc &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
NestedNameSpecifierLoc NextNode = Node.getPrefix();
if (!NextNode)
return false;
return InnerMatcher.matches(NextNode, Finder, Builder);
}
private:
const Matcher<NestedNameSpecifierLoc> InnerMatcher;
};
/// \brief Matches \c TypeLocs based on an inner matcher matching a certain
/// \c QualType.
///
/// Used to implement the \c loc() matcher.
class TypeLocTypeMatcher : public MatcherInterface<TypeLoc> {
public:
explicit TypeLocTypeMatcher(const Matcher<QualType> &InnerMatcher)
: InnerMatcher(InnerMatcher) {}
virtual bool matches(const TypeLoc &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
if (!Node)
return false;
return InnerMatcher.matches(Node.getType(), Finder, Builder);
}
private:
const Matcher<QualType> InnerMatcher;
};
/// \brief Matches nodes of type \c T for which the inner matcher matches on a
/// another node of type \c T that can be reached using a given traverse
/// function.
template <typename T>
class TypeTraverseMatcher : public MatcherInterface<T> {
public:
explicit TypeTraverseMatcher(const Matcher<QualType> &InnerMatcher,
QualType (T::*TraverseFunction)() const)
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
QualType NextNode = (Node.*TraverseFunction)();
if (NextNode.isNull())
return false;
return InnerMatcher.matches(NextNode, Finder, Builder);
}
private:
const Matcher<QualType> InnerMatcher;
QualType (T::*TraverseFunction)() const;
};
/// \brief Matches nodes of type \c T in a ..Loc hierarchy, for which the inner
/// matcher matches on a another node of type \c T that can be reached using a
/// given traverse function.
template <typename T>
class TypeLocTraverseMatcher : public MatcherInterface<T> {
public:
explicit TypeLocTraverseMatcher(const Matcher<TypeLoc> &InnerMatcher,
TypeLoc (T::*TraverseFunction)() const)
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
TypeLoc NextNode = (Node.*TraverseFunction)();
if (!NextNode)
return false;
return InnerMatcher.matches(NextNode, Finder, Builder);
}
private:
const Matcher<TypeLoc> InnerMatcher;
TypeLoc (T::*TraverseFunction)() const;
};
template <typename T, typename InnerT>
T makeTypeAllOfComposite(ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
return T(makeAllOfComposite<InnerT>(InnerMatchers));
}
} // end namespace internal
} // end namespace ast_matchers
} // end namespace clang

View File

@ -221,4 +221,69 @@
const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
/// \brief Creates a variadic matcher for both a specific \c Type as well as
/// the corresponding \c TypeLoc.
#define AST_TYPE_MATCHER(NodeType, MatcherName) \
const internal::VariadicDynCastAllOfMatcher<Type, NodeType> MatcherName; \
const internal::VariadicDynCastAllOfMatcher<TypeLoc, \
NodeType##Loc> MatcherName##Loc
/// \brief AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) defines
/// the matcher \c MatcherName that can be used to traverse from one \c Type
/// to another.
///
/// For a specific \c SpecificType, the traversal is done using
/// \c SpecificType::FunctionName. The existance of such a function determines
/// whether a corresponding matcher can be used on \c SpecificType.
#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) \
class Polymorphic##MatcherName##TypeMatcher { \
public: \
Polymorphic##MatcherName##TypeMatcher( \
const internal::Matcher<QualType> &InnerMatcher) \
: InnerMatcher(InnerMatcher) {} \
template <typename T> operator internal::Matcher<T>() { \
return internal::Matcher<T>(new internal::TypeTraverseMatcher<T>( \
InnerMatcher, &T::FunctionName)); \
} \
private: \
const internal::Matcher<QualType> InnerMatcher; \
}; \
class Variadic##MatcherName##TypeTraverseMatcher \
: public llvm::VariadicFunction< \
Polymorphic##MatcherName##TypeMatcher, \
internal::Matcher<QualType>, \
internal::makeTypeAllOfComposite< \
Polymorphic##MatcherName##TypeMatcher, QualType> > { \
public: \
Variadic##MatcherName##TypeTraverseMatcher() {} \
}; \
const Variadic##MatcherName##TypeTraverseMatcher MatcherName
/// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works
/// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs.
#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) \
class Polymorphic##MatcherName##TypeLocMatcher { \
public: \
Polymorphic##MatcherName##TypeLocMatcher( \
const internal::Matcher<TypeLoc> &InnerMatcher) \
: InnerMatcher(InnerMatcher) {} \
template <typename T> operator internal::Matcher<T>() { \
return internal::Matcher<T>(new internal::TypeLocTraverseMatcher<T>( \
InnerMatcher, &T::FunctionName##Loc)); \
} \
private: \
const internal::Matcher<TypeLoc> InnerMatcher; \
}; \
class Variadic##MatcherName##TypeLocTraverseMatcher \
: public llvm::VariadicFunction< \
Polymorphic##MatcherName##TypeLocMatcher, \
internal::Matcher<TypeLoc>, \
internal::makeTypeAllOfComposite< \
Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > { \
public: \
Variadic##MatcherName##TypeLocTraverseMatcher() {} \
}; \
const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc; \
AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type)
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H

View File

@ -0,0 +1,209 @@
//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Provides a dynamically typed node container that can be used to store
// an AST base node at runtime in the same storage in a type safe way.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
#include "llvm/Support/AlignOf.h"
namespace clang {
namespace ast_type_traits {
/// \brief A dynamically typed AST node container.
///
/// Stores an AST node in a type safe way. This allows writing code that
/// works with different kinds of AST nodes, despite the fact that they don't
/// have a common base class.
///
/// Use \c create(Node) to create a \c DynTypedNode from an AST node,
/// and \c get<T>() to retrieve the node as type T if the types match.
///
/// See \c NodeTypeTag for which node base types are currently supported;
/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
/// the supported base types.
class DynTypedNode {
public:
/// \brief Creates a \c DynTypedNode from \c Node.
template <typename T>
static DynTypedNode create(const T &Node) {
return BaseConverter<T>::create(Node);
}
/// \brief Retrieve the stored node as type \c T.
///
/// Returns NULL if the stored node does not have a type that is
/// convertible to \c T.
///
/// For types that have identity via their pointer in the AST
/// (like \c Stmt and \c Decl) the returned pointer points to the
/// referenced AST node.
/// For other types (like \c QualType) the value is stored directly
/// in the \c DynTypedNode, and the returned pointer points at
/// the storage inside DynTypedNode. For those nodes, do not
/// use the pointer outside the scope of the DynTypedNode.
template <typename T>
const T *get() const {
return BaseConverter<T>::get(Tag, Storage.buffer);
}
/// \brief Returns a pointer that identifies the stored AST node.
///
/// Note that this is not supported by all AST nodes. For AST nodes
/// that don't have a pointer-defined identity inside the AST, this
/// method returns NULL.
const void *getMemoizationData() const;
private:
/// \brief Takes care of converting from and to \c T.
template <typename T, typename EnablerT = void> struct BaseConverter;
/// \brief Supported base node types.
enum NodeTypeTag {
NT_Decl,
NT_Stmt,
NT_NestedNameSpecifier,
NT_NestedNameSpecifierLoc,
NT_QualType,
NT_Type,
NT_TypeLoc
} Tag;
/// \brief Stores the data of the node.
///
/// Note that we can store \c Decls and \c Stmts by pointer as they are
/// guaranteed to be unique pointers pointing to dedicated storage in the
/// AST. \c QualTypes on the other hand do not have storage or unique
/// pointers and thus need to be stored by value.
llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc>
Storage;
};
// FIXME: Pull out abstraction for the following.
template<typename T> struct DynTypedNode::BaseConverter<T,
typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
static const T *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_Decl)
return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
return NULL;
}
static DynTypedNode create(const Decl &Node) {
DynTypedNode Result;
Result.Tag = NT_Decl;
new (Result.Storage.buffer) const Decl*(&Node);
return Result;
}
};
template<typename T> struct DynTypedNode::BaseConverter<T,
typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
static const T *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_Stmt)
return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
return NULL;
}
static DynTypedNode create(const Stmt &Node) {
DynTypedNode Result;
Result.Tag = NT_Stmt;
new (Result.Storage.buffer) const Stmt*(&Node);
return Result;
}
};
template<typename T> struct DynTypedNode::BaseConverter<T,
typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
static const T *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_Type)
return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
return NULL;
}
static DynTypedNode create(const Type &Node) {
DynTypedNode Result;
Result.Tag = NT_Type;
new (Result.Storage.buffer) const Type*(&Node);
return Result;
}
};
template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_NestedNameSpecifier)
return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
return NULL;
}
static DynTypedNode create(const NestedNameSpecifier &Node) {
DynTypedNode Result;
Result.Tag = NT_NestedNameSpecifier;
new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
return Result;
}
};
template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
const char Storage[]) {
if (Tag == NT_NestedNameSpecifierLoc)
return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
return NULL;
}
static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
DynTypedNode Result;
Result.Tag = NT_NestedNameSpecifierLoc;
new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
return Result;
}
};
template<> struct DynTypedNode::BaseConverter<QualType, void> {
static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_QualType)
return reinterpret_cast<const QualType*>(Storage);
return NULL;
}
static DynTypedNode create(const QualType &Node) {
DynTypedNode Result;
Result.Tag = NT_QualType;
new (Result.Storage.buffer) QualType(Node);
return Result;
}
};
template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_TypeLoc)
return reinterpret_cast<const TypeLoc*>(Storage);
return NULL;
}
static DynTypedNode create(const TypeLoc &Node) {
DynTypedNode Result;
Result.Tag = NT_TypeLoc;
new (Result.Storage.buffer) TypeLoc(Node);
return Result;
}
};
// The only operation we allow on unsupported types is \c get.
// This allows to conveniently use \c DynTypedNode when having an arbitrary
// AST node that is not supported, but prevents misuse - a user cannot create
// a DynTypedNode from arbitrary types.
template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }
};
inline const void *DynTypedNode::getMemoizationData() const {
switch (Tag) {
case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
default: return NULL;
};
}
} // end namespace ast_type_traits
} // end namespace clang
#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H

View File

@ -23,6 +23,8 @@
namespace clang {
class TargetInfo;
//===----------------------------------------------------------------------===//
/// Common components of both fprintf and fscanf format strings.
namespace analyze_format_string {
@ -115,11 +117,14 @@ class ConversionSpecifier {
// C99 conversion specifiers.
cArg,
dArg,
DArg, // Apple extension
iArg,
IntArgBeg = cArg, IntArgEnd = iArg,
IntArgBeg = dArg, IntArgEnd = iArg,
oArg,
OArg, // Apple extension
uArg,
UArg, // Apple extension
xArg,
XArg,
UIntArgBeg = oArg, UIntArgEnd = XArg,
@ -157,7 +162,7 @@ class ConversionSpecifier {
ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
};
ConversionSpecifier(bool isPrintf)
ConversionSpecifier(bool isPrintf = true)
: IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
@ -189,10 +194,14 @@ class ConversionSpecifier {
return EndScanList ? EndScanList - Position : 1;
}
bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
const char *toString() const;
bool isPrintfKind() const { return IsPrintf; }
llvm::Optional<ConversionSpecifier> getStandardSpecifier() const;
protected:
bool IsPrintf;
@ -348,10 +357,12 @@ class FormatSpecifier {
bool usesPositionalArg() const { return UsesPositionalArg; }
bool hasValidLengthModifier() const;
bool hasValidLengthModifier(const TargetInfo &Target) const;
bool hasStandardLengthModifier() const;
llvm::Optional<LengthModifier> getCorrectedLengthModifier() const;
bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
bool hasStandardLengthConversionCombination() const;
@ -378,7 +389,6 @@ class PrintfConversionSpecifier :
: ConversionSpecifier(true, pos, k) {}
bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
bool isDoubleArg() const { return kind >= DoubleArgBeg &&
kind <= DoubleArgEnd; }
unsigned getLength() const {
@ -623,10 +633,12 @@ class FormatStringHandler {
};
bool ParsePrintfString(FormatStringHandler &H,
const char *beg, const char *end, const LangOptions &LO);
const char *beg, const char *end, const LangOptions &LO,
const TargetInfo &Target);
bool ParseScanfString(FormatStringHandler &H,
const char *beg, const char *end, const LangOptions &LO);
const char *beg, const char *end, const LangOptions &LO,
const TargetInfo &Target);
} // end analyze_format_string namespace
} // end clang namespace

View File

@ -132,7 +132,8 @@ class ThreadSafetyHandler {
/// \param Loc -- The location of the protected operation.
virtual void handleMutexNotHeld(const NamedDecl *D,
ProtectedOperationKind POK, Name LockName,
LockKind LK, SourceLocation Loc) {}
LockKind LK, SourceLocation Loc,
Name *PossibleMatch=0) {}
/// Warn when a function is called while an excluded mutex is locked. For
/// example, the mutex may be locked inside the function.

View File

@ -72,7 +72,7 @@ class AnalysisDeclContext {
/// AnalysisDeclContext. This may be null.
AnalysisDeclContextManager *Manager;
const Decl *D;
const Decl * const D;
OwningPtr<CFG> cfg, completeCFG;
OwningPtr<CFGStmtMap> cfgStmtMap;
@ -81,9 +81,6 @@ class AnalysisDeclContext {
CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
bool builtCFG, builtCompleteCFG;
OwningPtr<LiveVariables> liveness;
OwningPtr<LiveVariables> relaxedLiveness;
OwningPtr<ParentMap> PM;
OwningPtr<PseudoConstantAnalysis> PCA;
OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
@ -104,9 +101,15 @@ class AnalysisDeclContext {
~AnalysisDeclContext();
ASTContext &getASTContext() { return D->getASTContext(); }
ASTContext &getASTContext() const { return D->getASTContext(); }
const Decl *getDecl() const { return D; }
/// Return the AnalysisDeclContextManager (if any) that created
/// this AnalysisDeclContext.
AnalysisDeclContextManager *getManager() const {
return Manager;
}
/// Return the build options used to construct the CFG.
CFG::BuildOptions &getCFGBuildOptions() {
return cfgBuildOptions;
@ -234,9 +237,10 @@ class LocationContext : public llvm::FoldingSetNode {
const StackFrameContext *getCurrentStackFrame() const;
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
/// Return true if the current LocationContext has no caller context.
virtual bool inTopFrame() const;
static bool classof(const LocationContext*) { return true; }
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
public:
static void ProfileCommon(llvm::FoldingSetNodeID &ID,
@ -270,6 +274,9 @@ class StackFrameContext : public LocationContext {
const CFGBlock *getCallSiteBlock() const { return Block; }
/// Return true if the current LocationContext has no caller context.
virtual bool inTopFrame() const { return getParent() == 0; }
unsigned getIndex() const { return Index; }
void Profile(llvm::FoldingSetNodeID &ID);
@ -379,11 +386,17 @@ class AnalysisDeclContextManager {
ContextMap Contexts;
LocationContextManager LocContexts;
CFG::BuildOptions cfgBuildOptions;
/// Flag to indicate whether or not bodies should be synthesized
/// for well-known functions.
bool SynthesizeBodies;
public:
AnalysisDeclContextManager(bool useUnoptimizedCFG = false,
bool addImplicitDtors = false,
bool addInitializers = false);
bool addImplicitDtors = false,
bool addInitializers = false,
bool addTemporaryDtors = false,
bool synthesizeBodies = false);
~AnalysisDeclContextManager();
@ -396,6 +409,10 @@ class AnalysisDeclContextManager {
CFG::BuildOptions &getCFGBuildOptions() {
return cfgBuildOptions;
}
/// Return true if faux bodies should be synthesized for well-known
/// functions.
bool synthesizeBodies() const { return SynthesizeBodies; }
const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx,
LocationContext const *Parent,

View File

@ -88,8 +88,6 @@ class CFGElement {
return static_cast<const ElemTy*>(this);
return 0;
}
static bool classof(const CFGElement *E) { return true; }
};
class CFGStmt : public CFGElement {
@ -568,6 +566,7 @@ class CFG {
bool AddEHEdges;
bool AddInitializers;
bool AddImplicitDtors;
bool AddTemporaryDtors;
bool alwaysAdd(const Stmt *stmt) const {
return alwaysAddMask[stmt->getStmtClass()];
@ -587,7 +586,8 @@ class CFG {
: forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
,AddEHEdges(false)
,AddInitializers(false)
,AddImplicitDtors(false) {}
,AddImplicitDtors(false)
,AddTemporaryDtors(false) {}
};
/// \brief Provides a custom implementation of the iterator class to have the

View File

@ -0,0 +1,46 @@
//= ObjCNoReturn.h - Handling of Cocoa APIs known not to return --*- 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 special handling of recognizing ObjC API hooks that
// do not return but aren't marked as such in API headers.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
#define LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
#include "clang/Basic/IdentifierTable.h"
namespace clang {
class ASTContext;
class ObjCMessageExpr;
class ObjCNoReturn {
/// Cached "raise" selector.
Selector RaiseSel;
/// Cached identifier for "NSException".
IdentifierInfo *NSExceptionII;
enum { NUM_RAISE_SELECTORS = 2 };
/// Cached set of selectors in NSException that are 'noreturn'.
Selector NSExceptionInstanceRaiseSelectors[NUM_RAISE_SELECTORS];
public:
ObjCNoReturn(ASTContext &C);
/// Return true if the given message expression is known to never
/// return.
bool isImplicitNoReturn(const ObjCMessageExpr *ME);
};
}
#endif

View File

@ -140,8 +140,6 @@ class ProgramPoint {
return ID.ComputeHash();
}
static bool classof(const ProgramPoint*) { return true; }
bool operator==(const ProgramPoint & RHS) const {
return Data1 == RHS.Data1 &&
Data2 == RHS.Data2 &&
@ -213,7 +211,9 @@ class StmtPoint : public ProgramPoint {
public:
StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
const ProgramPointTag *tag)
: ProgramPoint(S, p2, k, L, tag) {}
: ProgramPoint(S, p2, k, L, tag) {
assert(S);
}
const Stmt *getStmt() const { return (const Stmt*) getData1(); }
@ -461,6 +461,7 @@ class PostImplicitCall : public ImplicitCallPoint {
};
/// Represents a point when we begin processing an inlined call.
/// CallEnter uses the caller's location context.
class CallEnter : public ProgramPoint {
public:
CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,

View File

@ -190,7 +190,7 @@ def Availability : InheritableAttr {
[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
return llvm::StringSwitch<llvm::StringRef>(Platform)
.Case("ios", "iOS")
.Case("macosx", "Mac OS X")
.Case("macosx", "OS X")
.Default(llvm::StringRef());
} }];
}
@ -341,6 +341,11 @@ def Final : InheritableAttr {
let SemaHandler = 0;
}
def MinSize : InheritableAttr {
let Spellings = [GNU<"minsize">];
let Subjects = [Function];
}
def Format : InheritableAttr {
let Spellings = [GNU<"format">];
let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,
@ -528,6 +533,11 @@ def ObjCReturnsInnerPointer : Attr {
let Subjects = [ObjCMethod];
}
def ObjCRequiresSuper : InheritableAttr {
let Spellings = [GNU<"objc_requires_super">];
let Subjects = [ObjCMethod];
}
def ObjCRootClass : Attr {
let Spellings = [GNU<"objc_root_class">];
let Subjects = [ObjCInterface];
@ -556,6 +566,10 @@ def Packed : InheritableAttr {
let Spellings = [GNU<"packed">];
}
def PnaclCall : InheritableAttr {
let Spellings = [GNU<"pnaclcall">];
}
def Pcs : InheritableAttr {
let Spellings = [GNU<"pcs">];
let Args = [EnumArgument<"PCS", "PCSType",

View File

@ -41,6 +41,7 @@
// J -> jmp_buf
// SJ -> sigjmp_buf
// K -> ucontext_t
// p -> pid_t
// . -> "...". This may only occur at the end of the function list.
//
// Types may be prefixed with the following modifiers:
@ -388,6 +389,7 @@ 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_bswap16, "UsUs", "nc")
BUILTIN(__builtin_bswap32, "UiUi", "nc")
BUILTIN(__builtin_bswap64, "ULLiULLi", "nc")
@ -478,6 +480,7 @@ BUILTIN(__builtin_expect, "LiLiLi" , "nc")
BUILTIN(__builtin_prefetch, "vvC*.", "nc")
BUILTIN(__builtin_readcyclecounter, "ULLi", "n")
BUILTIN(__builtin_trap, "v", "nr")
BUILTIN(__builtin_debugtrap, "v", "n")
BUILTIN(__builtin_unreachable, "v", "nr")
BUILTIN(__builtin_shufflevector, "v." , "nc")
BUILTIN(__builtin_alloca, "v*z" , "n")
@ -735,7 +738,7 @@ LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_LANGUAGES)
LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_LANGUAGES)
// POSIX unistd.h
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES)
LIBBUILTIN(vfork, "i", "fj", "unistd.h", ALL_LANGUAGES)
LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_LANGUAGES)
// POSIX setjmp.h
// In some systems setjmp is a macro that expands to _setjmp. We undefine
@ -826,9 +829,13 @@ LIBBUILTIN(atan2, "ddd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(atan2l, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(atan2f, "fff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceil, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceill, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceilf, "ff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceil, "dd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceill, "LdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceilf, "ff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(copysign, "ddd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(copysignl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(copysignf, "fff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(cos, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(cosl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
@ -838,37 +845,53 @@ LIBBUILTIN(exp, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(expl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(expf, "ff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fabs, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fabsl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fabsf, "ff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(exp2, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(exp2l, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(exp2f, "ff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(floor, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(floorl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(floorf, "ff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fabs, "dd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fabsl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fabsf, "ff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(floor, "dd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(floorl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(floorf, "ff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fma, "dddd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmal, "LdLdLdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmaf, "ffff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmax, "ddd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmaxl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmaxf, "fff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmax, "ddd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmaxl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmaxf, "fff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmin, "ddd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fminl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fminf, "fff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmin, "ddd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fminl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fminf, "fff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(log, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(logl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(logf, "ff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(log2, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(log2l, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(log2f, "ff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(nearbyint, "dd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(nearbyintl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(nearbyintf, "ff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(pow, "ddd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(powl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(powf, "fff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(round, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(roundl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(roundf, "ff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(rint, "dd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(rintl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(rintf, "ff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(round, "dd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(roundl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(roundf, "ff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(sin, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(sinl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
@ -882,6 +905,10 @@ LIBBUILTIN(tan, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(tanl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(tanf, "ff", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(trunc, "dd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(truncl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(truncf, "ff", "fc", "math.h", ALL_LANGUAGES)
// Blocks runtime Builtin math library functions
LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)

View File

@ -14,6 +14,8 @@
// The format of this database matches clang/Basic/Builtins.def.
// MIPS DSP Rev 1
// Add/subtract with optional saturation
BUILTIN(__builtin_mips_addu_qb, "V4ScV4ScV4Sc", "n")
BUILTIN(__builtin_mips_addu_s_qb, "V4ScV4ScV4Sc", "n")
@ -122,4 +124,65 @@ BUILTIN(__builtin_mips_lbux, "iv*i", "n")
BUILTIN(__builtin_mips_lhx, "iv*i", "n")
BUILTIN(__builtin_mips_lwx, "iv*i", "n")
// MIPS DSP Rev 2
BUILTIN(__builtin_mips_absq_s_qb, "V4ScV4Sc", "n")
BUILTIN(__builtin_mips_addqh_ph, "V2sV2sV2s", "nc")
BUILTIN(__builtin_mips_addqh_r_ph, "V2sV2sV2s", "nc")
BUILTIN(__builtin_mips_addqh_w, "iii", "nc")
BUILTIN(__builtin_mips_addqh_r_w, "iii", "nc")
BUILTIN(__builtin_mips_addu_ph, "V2sV2sV2s", "n")
BUILTIN(__builtin_mips_addu_s_ph, "V2sV2sV2s", "n")
BUILTIN(__builtin_mips_adduh_qb, "V4ScV4ScV4Sc", "nc")
BUILTIN(__builtin_mips_adduh_r_qb, "V4ScV4ScV4Sc", "nc")
BUILTIN(__builtin_mips_append, "iiiIi", "nc")
BUILTIN(__builtin_mips_balign, "iiiIi", "nc")
BUILTIN(__builtin_mips_cmpgdu_eq_qb, "iV4ScV4Sc", "n")
BUILTIN(__builtin_mips_cmpgdu_lt_qb, "iV4ScV4Sc", "n")
BUILTIN(__builtin_mips_cmpgdu_le_qb, "iV4ScV4Sc", "n")
BUILTIN(__builtin_mips_dpa_w_ph, "LLiLLiV2sV2s", "nc")
BUILTIN(__builtin_mips_dps_w_ph, "LLiLLiV2sV2s", "nc")
BUILTIN(__builtin_mips_dpaqx_s_w_ph, "LLiLLiV2sV2s", "n")
BUILTIN(__builtin_mips_dpaqx_sa_w_ph, "LLiLLiV2sV2s", "n")
BUILTIN(__builtin_mips_dpax_w_ph, "LLiLLiV2sV2s", "nc")
BUILTIN(__builtin_mips_dpsx_w_ph, "LLiLLiV2sV2s", "nc")
BUILTIN(__builtin_mips_dpsqx_s_w_ph, "LLiLLiV2sV2s", "n")
BUILTIN(__builtin_mips_dpsqx_sa_w_ph, "LLiLLiV2sV2s", "n")
BUILTIN(__builtin_mips_mul_ph, "V2sV2sV2s", "n")
BUILTIN(__builtin_mips_mul_s_ph, "V2sV2sV2s", "n")
BUILTIN(__builtin_mips_mulq_rs_w, "iii", "n")
BUILTIN(__builtin_mips_mulq_s_ph, "V2sV2sV2s", "n")
BUILTIN(__builtin_mips_mulq_s_w, "iii", "n")
BUILTIN(__builtin_mips_mulsa_w_ph, "LLiLLiV2sV2s", "nc")
BUILTIN(__builtin_mips_precr_qb_ph, "V4ScV2sV2s", "n")
BUILTIN(__builtin_mips_precr_sra_ph_w, "V2siiIi", "nc")
BUILTIN(__builtin_mips_precr_sra_r_ph_w, "V2siiIi", "nc")
BUILTIN(__builtin_mips_prepend, "iiiIi", "nc")
BUILTIN(__builtin_mips_shra_qb, "V4ScV4Sci", "nc")
BUILTIN(__builtin_mips_shra_r_qb, "V4ScV4Sci", "nc")
BUILTIN(__builtin_mips_shrl_ph, "V2sV2si", "nc")
BUILTIN(__builtin_mips_subqh_ph, "V2sV2sV2s", "nc")
BUILTIN(__builtin_mips_subqh_r_ph, "V2sV2sV2s", "nc")
BUILTIN(__builtin_mips_subqh_w, "iii", "nc")
BUILTIN(__builtin_mips_subqh_r_w, "iii", "nc")
BUILTIN(__builtin_mips_subu_ph, "V2sV2sV2s", "n")
BUILTIN(__builtin_mips_subu_s_ph, "V2sV2sV2s", "n")
BUILTIN(__builtin_mips_subuh_qb, "V4ScV4ScV4Sc", "nc")
BUILTIN(__builtin_mips_subuh_r_qb, "V4ScV4ScV4Sc", "nc")
#undef BUILTIN

View File

@ -14,6 +14,7 @@
// The format of this database matches clang/Basic/Builtins.def.
// Builtins retained from previous PTX back-end
BUILTIN(__builtin_ptx_read_tid_x, "i", "nc")
BUILTIN(__builtin_ptx_read_tid_y, "i", "nc")
BUILTIN(__builtin_ptx_read_tid_z, "i", "nc")
@ -59,4 +60,249 @@ BUILTIN(__builtin_ptx_read_pm3, "i", "n")
BUILTIN(__builtin_ptx_bar_sync, "vi", "n")
// Builtins exposed as part of NVVM
BUILTIN(__syncthreads, "v", "n")
BUILTIN(__nvvm_bar0, "v", "n")
BUILTIN(__nvvm_bar0_popc, "ii", "n")
BUILTIN(__nvvm_bar0_and, "ii", "n")
BUILTIN(__nvvm_bar0_or, "ii", "n")
BUILTIN(__nvvm_membar_cta, "v", "n")
BUILTIN(__nvvm_membar_gl, "v", "n")
BUILTIN(__nvvm_membar_sys, "v", "n")
BUILTIN(__nvvm_popc_i, "ii", "nc")
BUILTIN(__nvvm_popc_ll, "LiLi", "nc")
BUILTIN(__nvvm_prmt, "UiUiUiUi", "nc")
BUILTIN(__nvvm_min_i, "iii", "nc")
BUILTIN(__nvvm_min_ui, "UiUiUi", "nc")
BUILTIN(__nvvm_min_ll, "LLiLLiLLi", "nc")
BUILTIN(__nvvm_min_ull, "ULLiULLiULLi", "nc")
BUILTIN(__nvvm_max_i, "iii", "nc")
BUILTIN(__nvvm_max_ui, "UiUiUi", "nc")
BUILTIN(__nvvm_max_ll, "LLiLLiLLi", "nc")
BUILTIN(__nvvm_max_ull, "ULLiULLiULLi", "nc")
BUILTIN(__nvvm_mulhi_i, "iii", "nc")
BUILTIN(__nvvm_mulhi_ui, "UiUiUi", "nc")
BUILTIN(__nvvm_mulhi_ll, "LLiLLiLLi", "nc")
BUILTIN(__nvvm_mulhi_ull, "ULLiULLiULLi", "nc")
BUILTIN(__nvvm_mul24_i, "iii", "nc")
BUILTIN(__nvvm_mul24_ui, "UiUiUi", "nc")
BUILTIN(__nvvm_brev32, "UiUi", "nc")
BUILTIN(__nvvm_brev64, "ULLiULLi", "nc")
BUILTIN(__nvvm_sad_i, "iiii", "nc")
BUILTIN(__nvvm_sad_ui, "UiUiUiUi", "nc")
BUILTIN(__nvvm_abs_i, "ii", "nc")
BUILTIN(__nvvm_abs_ll, "LiLi", "nc")
BUILTIN(__nvvm_floor_ftz_f, "ff", "nc")
BUILTIN(__nvvm_floor_f, "ff", "nc")
BUILTIN(__nvvm_floor_d, "dd", "nc")
BUILTIN(__nvvm_fabs_ftz_f, "ff", "nc")
BUILTIN(__nvvm_fabs_f, "ff", "nc")
BUILTIN(__nvvm_fabs_d, "dd", "nc")
BUILTIN(__nvvm_rcp_approx_ftz_d, "dd", "nc")
BUILTIN(__nvvm_fmin_ftz_f, "fff", "nc")
BUILTIN(__nvvm_fmin_f, "fff", "nc")
BUILTIN(__nvvm_fmax_ftz_f, "fff", "nc")
BUILTIN(__nvvm_fmax_f, "fff", "nc")
BUILTIN(__nvvm_rsqrt_approx_ftz_f, "ff", "nc")
BUILTIN(__nvvm_rsqrt_approx_f, "ff", "nc")
BUILTIN(__nvvm_fmin_d, "ddd", "nc")
BUILTIN(__nvvm_fmax_d, "ddd", "nc")
BUILTIN(__nvvm_rsqrt_approx_d, "dd", "nc")
BUILTIN(__nvvm_ceil_d, "dd", "nc")
BUILTIN(__nvvm_trunc_d, "dd", "nc")
BUILTIN(__nvvm_round_d, "dd", "nc")
BUILTIN(__nvvm_ex2_approx_d, "dd", "nc")
BUILTIN(__nvvm_lg2_approx_d, "dd", "nc")
BUILTIN(__nvvm_round_ftz_f, "ff", "nc")
BUILTIN(__nvvm_round_f, "ff", "nc")
BUILTIN(__nvvm_ex2_approx_ftz_f, "ff", "nc")
BUILTIN(__nvvm_ex2_approx_f, "ff", "nc")
BUILTIN(__nvvm_lg2_approx_ftz_f, "ff", "nc")
BUILTIN(__nvvm_lg2_approx_f, "ff", "nc")
BUILTIN(__nvvm_sin_approx_ftz_f, "ff", "nc")
BUILTIN(__nvvm_sin_approx_f, "ff", "nc")
BUILTIN(__nvvm_cos_approx_ftz_f, "ff", "nc")
BUILTIN(__nvvm_cos_approx_f, "ff", "nc")
BUILTIN(__nvvm_trunc_ftz_f, "ff", "nc")
BUILTIN(__nvvm_trunc_f, "ff", "nc")
BUILTIN(__nvvm_ceil_ftz_f, "ff", "nc")
BUILTIN(__nvvm_ceil_f, "ff", "nc")
BUILTIN(__nvvm_saturate_d, "dd", "nc")
BUILTIN(__nvvm_saturate_ftz_f, "ff", "nc")
BUILTIN(__nvvm_saturate_f, "ff", "nc")
BUILTIN(__nvvm_fma_rn_ftz_f, "ffff", "nc")
BUILTIN(__nvvm_fma_rn_f, "ffff", "nc")
BUILTIN(__nvvm_fma_rz_ftz_f, "ffff", "nc")
BUILTIN(__nvvm_fma_rz_f, "ffff", "nc")
BUILTIN(__nvvm_fma_rm_ftz_f, "ffff", "nc")
BUILTIN(__nvvm_fma_rm_f, "ffff", "nc")
BUILTIN(__nvvm_fma_rp_ftz_f, "ffff", "nc")
BUILTIN(__nvvm_fma_rp_f, "ffff", "nc")
BUILTIN(__nvvm_fma_rn_d, "dddd", "nc")
BUILTIN(__nvvm_fma_rz_d, "dddd", "nc")
BUILTIN(__nvvm_fma_rm_d, "dddd", "nc")
BUILTIN(__nvvm_fma_rp_d, "dddd", "nc")
BUILTIN(__nvvm_div_approx_ftz_f, "fff", "nc")
BUILTIN(__nvvm_div_approx_f, "fff", "nc")
BUILTIN(__nvvm_div_rn_ftz_f, "fff", "nc")
BUILTIN(__nvvm_div_rn_f, "fff", "nc")
BUILTIN(__nvvm_div_rz_ftz_f, "fff", "nc")
BUILTIN(__nvvm_div_rz_f, "fff", "nc")
BUILTIN(__nvvm_div_rm_ftz_f, "fff", "nc")
BUILTIN(__nvvm_div_rm_f, "fff", "nc")
BUILTIN(__nvvm_div_rp_ftz_f, "fff", "nc")
BUILTIN(__nvvm_div_rp_f, "fff", "nc")
BUILTIN(__nvvm_rcp_rn_ftz_f, "ff", "nc")
BUILTIN(__nvvm_rcp_rn_f, "ff", "nc")
BUILTIN(__nvvm_rcp_rz_ftz_f, "ff", "nc")
BUILTIN(__nvvm_rcp_rz_f, "ff", "nc")
BUILTIN(__nvvm_rcp_rm_ftz_f, "ff", "nc")
BUILTIN(__nvvm_rcp_rm_f, "ff", "nc")
BUILTIN(__nvvm_rcp_rp_ftz_f, "ff", "nc")
BUILTIN(__nvvm_rcp_rp_f, "ff", "nc")
BUILTIN(__nvvm_sqrt_rn_ftz_f, "ff", "nc")
BUILTIN(__nvvm_sqrt_rn_f, "ff", "nc")
BUILTIN(__nvvm_sqrt_rz_ftz_f, "ff", "nc")
BUILTIN(__nvvm_sqrt_rz_f, "ff", "nc")
BUILTIN(__nvvm_sqrt_rm_ftz_f, "ff", "nc")
BUILTIN(__nvvm_sqrt_rm_f, "ff", "nc")
BUILTIN(__nvvm_sqrt_rp_ftz_f, "ff", "nc")
BUILTIN(__nvvm_sqrt_rp_f, "ff", "nc")
BUILTIN(__nvvm_div_rn_d, "ddd", "nc")
BUILTIN(__nvvm_div_rz_d, "ddd", "nc")
BUILTIN(__nvvm_div_rm_d, "ddd", "nc")
BUILTIN(__nvvm_div_rp_d, "ddd", "nc")
BUILTIN(__nvvm_rcp_rn_d, "dd", "nc")
BUILTIN(__nvvm_rcp_rz_d, "dd", "nc")
BUILTIN(__nvvm_rcp_rm_d, "dd", "nc")
BUILTIN(__nvvm_rcp_rp_d, "dd", "nc")
BUILTIN(__nvvm_sqrt_rn_d, "dd", "nc")
BUILTIN(__nvvm_sqrt_rz_d, "dd", "nc")
BUILTIN(__nvvm_sqrt_rm_d, "dd", "nc")
BUILTIN(__nvvm_sqrt_rp_d, "dd", "nc")
BUILTIN(__nvvm_sqrt_approx_ftz_f, "ff", "nc")
BUILTIN(__nvvm_sqrt_approx_f, "ff", "nc")
BUILTIN(__nvvm_add_rn_d, "ddd", "nc")
BUILTIN(__nvvm_add_rz_d, "ddd", "nc")
BUILTIN(__nvvm_add_rm_d, "ddd", "nc")
BUILTIN(__nvvm_add_rp_d, "ddd", "nc")
BUILTIN(__nvvm_mul_rn_d, "ddd", "nc")
BUILTIN(__nvvm_mul_rz_d, "ddd", "nc")
BUILTIN(__nvvm_mul_rm_d, "ddd", "nc")
BUILTIN(__nvvm_mul_rp_d, "ddd", "nc")
BUILTIN(__nvvm_add_rm_ftz_f, "fff", "nc")
BUILTIN(__nvvm_add_rm_f, "fff", "nc")
BUILTIN(__nvvm_add_rp_ftz_f, "fff", "nc")
BUILTIN(__nvvm_add_rp_f, "fff", "nc")
BUILTIN(__nvvm_mul_rm_ftz_f, "fff", "nc")
BUILTIN(__nvvm_mul_rm_f, "fff", "nc")
BUILTIN(__nvvm_mul_rp_ftz_f, "fff", "nc")
BUILTIN(__nvvm_mul_rp_f, "fff", "nc")
BUILTIN(__nvvm_add_rn_ftz_f, "fff", "nc")
BUILTIN(__nvvm_add_rn_f, "fff", "nc")
BUILTIN(__nvvm_add_rz_ftz_f, "fff", "nc")
BUILTIN(__nvvm_add_rz_f, "fff", "nc")
BUILTIN(__nvvm_mul_rn_ftz_f, "fff", "nc")
BUILTIN(__nvvm_mul_rn_f, "fff", "nc")
BUILTIN(__nvvm_mul_rz_ftz_f, "fff", "nc")
BUILTIN(__nvvm_mul_rz_f, "fff", "nc")
BUILTIN(__nvvm_d2f_rn_ftz, "fd", "nc")
BUILTIN(__nvvm_d2f_rn, "fd", "nc")
BUILTIN(__nvvm_d2f_rz_ftz, "fd", "nc")
BUILTIN(__nvvm_d2f_rz, "fd", "nc")
BUILTIN(__nvvm_d2f_rm_ftz, "fd", "nc")
BUILTIN(__nvvm_d2f_rm, "fd", "nc")
BUILTIN(__nvvm_d2f_rp_ftz, "fd", "nc")
BUILTIN(__nvvm_d2f_rp, "fd", "nc")
BUILTIN(__nvvm_d2i_rn, "id", "nc")
BUILTIN(__nvvm_d2i_rz, "id", "nc")
BUILTIN(__nvvm_d2i_rm, "id", "nc")
BUILTIN(__nvvm_d2i_rp, "id", "nc")
BUILTIN(__nvvm_d2ui_rn, "Uid", "nc")
BUILTIN(__nvvm_d2ui_rz, "Uid", "nc")
BUILTIN(__nvvm_d2ui_rm, "Uid", "nc")
BUILTIN(__nvvm_d2ui_rp, "Uid", "nc")
BUILTIN(__nvvm_i2d_rn, "di", "nc")
BUILTIN(__nvvm_i2d_rz, "di", "nc")
BUILTIN(__nvvm_i2d_rm, "di", "nc")
BUILTIN(__nvvm_i2d_rp, "di", "nc")
BUILTIN(__nvvm_ui2d_rn, "dUi", "nc")
BUILTIN(__nvvm_ui2d_rz, "dUi", "nc")
BUILTIN(__nvvm_ui2d_rm, "dUi", "nc")
BUILTIN(__nvvm_ui2d_rp, "dUi", "nc")
BUILTIN(__nvvm_f2i_rn_ftz, "if", "nc")
BUILTIN(__nvvm_f2i_rn, "if", "nc")
BUILTIN(__nvvm_f2i_rz_ftz, "if", "nc")
BUILTIN(__nvvm_f2i_rz, "if", "nc")
BUILTIN(__nvvm_f2i_rm_ftz, "if", "nc")
BUILTIN(__nvvm_f2i_rm, "if", "nc")
BUILTIN(__nvvm_f2i_rp_ftz, "if", "nc")
BUILTIN(__nvvm_f2i_rp, "if", "nc")
BUILTIN(__nvvm_f2ui_rn_ftz, "Uif", "nc")
BUILTIN(__nvvm_f2ui_rn, "Uif", "nc")
BUILTIN(__nvvm_f2ui_rz_ftz, "Uif", "nc")
BUILTIN(__nvvm_f2ui_rz, "Uif", "nc")
BUILTIN(__nvvm_f2ui_rm_ftz, "Uif", "nc")
BUILTIN(__nvvm_f2ui_rm, "Uif", "nc")
BUILTIN(__nvvm_f2ui_rp_ftz, "Uif", "nc")
BUILTIN(__nvvm_f2ui_rp, "Uif", "nc")
BUILTIN(__nvvm_i2f_rn, "fi", "nc")
BUILTIN(__nvvm_i2f_rz, "fi", "nc")
BUILTIN(__nvvm_i2f_rm, "fi", "nc")
BUILTIN(__nvvm_i2f_rp, "fi", "nc")
BUILTIN(__nvvm_ui2f_rn, "fUi", "nc")
BUILTIN(__nvvm_ui2f_rz, "fUi", "nc")
BUILTIN(__nvvm_ui2f_rm, "fUi", "nc")
BUILTIN(__nvvm_ui2f_rp, "fUi", "nc")
BUILTIN(__nvvm_lohi_i2d, "dii", "nc")
BUILTIN(__nvvm_d2i_lo, "id", "nc")
BUILTIN(__nvvm_d2i_hi, "id", "nc")
BUILTIN(__nvvm_f2ll_rn_ftz, "LLif", "nc")
BUILTIN(__nvvm_f2ll_rn, "LLif", "nc")
BUILTIN(__nvvm_f2ll_rz_ftz, "LLif", "nc")
BUILTIN(__nvvm_f2ll_rz, "LLif", "nc")
BUILTIN(__nvvm_f2ll_rm_ftz, "LLif", "nc")
BUILTIN(__nvvm_f2ll_rm, "LLif", "nc")
BUILTIN(__nvvm_f2ll_rp_ftz, "LLif", "nc")
BUILTIN(__nvvm_f2ll_rp, "LLif", "nc")
BUILTIN(__nvvm_f2ull_rn_ftz, "ULLif", "nc")
BUILTIN(__nvvm_f2ull_rn, "ULLif", "nc")
BUILTIN(__nvvm_f2ull_rz_ftz, "ULLif", "nc")
BUILTIN(__nvvm_f2ull_rz, "ULLif", "nc")
BUILTIN(__nvvm_f2ull_rm_ftz, "ULLif", "nc")
BUILTIN(__nvvm_f2ull_rm, "ULLif", "nc")
BUILTIN(__nvvm_f2ull_rp_ftz, "ULLif", "nc")
BUILTIN(__nvvm_f2ull_rp, "ULLif", "nc")
BUILTIN(__nvvm_d2ll_rn, "LLid", "nc")
BUILTIN(__nvvm_d2ll_rz, "LLid", "nc")
BUILTIN(__nvvm_d2ll_rm, "LLid", "nc")
BUILTIN(__nvvm_d2ll_rp, "LLid", "nc")
BUILTIN(__nvvm_d2ull_rn, "ULLid", "nc")
BUILTIN(__nvvm_d2ull_rz, "ULLid", "nc")
BUILTIN(__nvvm_d2ull_rm, "ULLid", "nc")
BUILTIN(__nvvm_d2ull_rp, "ULLid", "nc")
BUILTIN(__nvvm_ll2f_rn, "fLLi", "nc")
BUILTIN(__nvvm_ll2f_rz, "fLLi", "nc")
BUILTIN(__nvvm_ll2f_rm, "fLLi", "nc")
BUILTIN(__nvvm_ll2f_rp, "fLLi", "nc")
BUILTIN(__nvvm_ull2f_rn, "fULLi", "nc")
BUILTIN(__nvvm_ull2f_rz, "fULLi", "nc")
BUILTIN(__nvvm_ull2f_rm, "fULLi", "nc")
BUILTIN(__nvvm_ull2f_rp, "fULLi", "nc")
BUILTIN(__nvvm_ll2d_rn, "dLLi", "nc")
BUILTIN(__nvvm_ll2d_rz, "dLLi", "nc")
BUILTIN(__nvvm_ll2d_rm, "dLLi", "nc")
BUILTIN(__nvvm_ll2d_rp, "dLLi", "nc")
BUILTIN(__nvvm_ull2d_rn, "dULLi", "nc")
BUILTIN(__nvvm_ull2d_rz, "dULLi", "nc")
BUILTIN(__nvvm_ull2d_rm, "dULLi", "nc")
BUILTIN(__nvvm_ull2d_rp, "dULLi", "nc")
BUILTIN(__nvvm_f2h_rn_ftz, "Usf", "nc")
BUILTIN(__nvvm_f2h_rn, "Usf", "nc")
BUILTIN(__nvvm_h2f, "fUs", "nc")
BUILTIN(__nvvm_bitcast_i2f, "fi", "nc")
BUILTIN(__nvvm_bitcast_f2i, "if", "nc")
BUILTIN(__nvvm_bitcast_ll2d, "dLLi", "nc")
BUILTIN(__nvvm_bitcast_d2ll, "LLid", "nc")
#undef BUILTIN

View File

@ -613,6 +613,12 @@ BUILTIN(__builtin_ia32_gatherd_d256, "V8iV8iV8iC*V8iV8iIc", "")
BUILTIN(__builtin_ia32_gatherq_d, "V4iV4iV4iC*V2LLiV4iIc", "")
BUILTIN(__builtin_ia32_gatherq_d256, "V4iV4iV4iC*V4LLiV4iIc", "")
// F16C
BUILTIN(__builtin_ia32_vcvtps2ph, "V8sV4fIi", "")
BUILTIN(__builtin_ia32_vcvtps2ph256, "V8sV8fIi", "")
BUILTIN(__builtin_ia32_vcvtph2ps, "V4fV8s", "")
BUILTIN(__builtin_ia32_vcvtph2ps256, "V8fV8s", "")
// RDRAND
BUILTIN(__builtin_ia32_rdrand16_step, "UiUs*", "")
BUILTIN(__builtin_ia32_rdrand32_step, "UiUi*", "")
@ -730,5 +736,8 @@ BUILTIN(__builtin_ia32_vfrczps, "V4fV4f", "")
BUILTIN(__builtin_ia32_vfrczpd, "V2dV2d", "")
BUILTIN(__builtin_ia32_vfrczps256, "V8fV8f", "")
BUILTIN(__builtin_ia32_vfrczpd256, "V4dV4d", "")
BUILTIN(__builtin_ia32_xbegin, "i", "")
BUILTIN(__builtin_ia32_xend, "v", "")
BUILTIN(__builtin_ia32_xabort, "vIc", "")
#undef BUILTIN

View File

@ -147,7 +147,6 @@ ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
#ifdef CLANG_NEEDS_THESE_ONE_DAY
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
@ -159,7 +158,9 @@ ConversionResult ConvertUTF32toUTF16 (
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
Boolean isLegalUTF8String(const UTF8 *source, const UTF8 *sourceEnd);
Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
unsigned getNumBytesForUTF8(UTF8 firstByte);
#ifdef __cplusplus
}
@ -175,11 +176,13 @@ namespace clang {
* Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on
* WideCharWidth. The converted data is written to ResultPtr, which needs to
* point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
* ResultPtr will point one after the end of the copied string.
* ResultPtr will point one after the end of the copied string. On failure,
* ResultPtr will not be changed, and ErrorPtr will be set to the location of
* the first character which could not be converted.
* \return true on success.
*/
bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
char *&ResultPtr);
char *&ResultPtr, const UTF8 *&ErrorPtr);
/**
* Convert an Unicode code point to UTF8 sequence.
@ -194,7 +197,6 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
}
#endif
#endif

View File

@ -16,6 +16,7 @@
#define LLVM_CLANG_DIAGNOSTIC_H
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@ -29,6 +30,7 @@
namespace clang {
class DiagnosticConsumer;
class DiagnosticBuilder;
class DiagnosticOptions;
class IdentifierInfo;
class DeclContext;
class LangOptions;
@ -160,13 +162,6 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
ak_qualtype_pair ///< pair<QualType, QualType>
};
/// \brief Specifies which overload candidates to display when overload
/// resolution fails.
enum OverloadsShown {
Ovl_All, ///< Show all overloads.
Ovl_Best ///< Show just the "best" overload candidates.
};
/// \brief Represents on argument value, which is a union discriminated
/// by ArgumentKind, with a value.
typedef std::pair<ArgumentKind, intptr_t> ArgumentValue;
@ -190,6 +185,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
// backtrace stack, 0 -> no limit.
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
IntrusiveRefCntPtr<DiagnosticIDs> Diags;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticConsumer *Client;
bool OwnsDiagClient;
SourceManager *SourceMgr;
@ -341,6 +337,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
public:
explicit DiagnosticsEngine(
const IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
DiagnosticOptions *DiagOpts,
DiagnosticConsumer *client = 0,
bool ShouldOwnClient = true);
~DiagnosticsEngine();
@ -349,6 +346,9 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
return Diags;
}
/// \brief Retrieve the diagnostic options.
DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; }
DiagnosticConsumer *getClient() { return Client; }
const DiagnosticConsumer *getClient() const { return Client; }
@ -478,10 +478,13 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
}
OverloadsShown getShowOverloads() const { return ShowOverloads; }
/// \brief Pretend that the last diagnostic issued was ignored.
/// \brief Pretend that the last diagnostic issued was ignored, so any
/// subsequent notes will be suppressed.
///
/// This can be used by clients who suppress diagnostics themselves.
void setLastDiagnosticIgnored() {
if (LastDiagLevel == DiagnosticIDs::Fatal)
FatalErrorOccurred = true;
LastDiagLevel = DiagnosticIDs::Ignored;
}
@ -584,7 +587,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
const char *Argument, unsigned ArgLen,
const ArgumentValue *PrevArgs, unsigned NumPrevArgs,
SmallVectorImpl<char> &Output,
SmallVectorImpl<intptr_t> &QualTypeVals) const {
ArrayRef<intptr_t> QualTypeVals) const {
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen,
PrevArgs, NumPrevArgs, Output, ArgToStringCookie,
QualTypeVals);
@ -837,7 +840,7 @@ class DiagnosticBuilder {
/// call to ForceEmit.
mutable bool IsForceEmit;
void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
void operator=(const DiagnosticBuilder &) LLVM_DELETED_FUNCTION;
friend class DiagnosticsEngine;
DiagnosticBuilder()
@ -961,6 +964,10 @@ class DiagnosticBuilder {
"Too many arguments to diagnostic!");
DiagObj->DiagFixItHints[NumFixits++] = Hint;
}
bool hasMaxRanges() const {
return NumRanges == DiagnosticsEngine::MaxRanges;
}
};
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,

View File

@ -137,7 +137,7 @@ def err_odr_function_type_inconsistent : Error<
def warn_odr_tag_type_inconsistent : Warning<
"type %0 has incompatible definitions in different translation units">;
def note_odr_tag_kind_here: Note<
"%0 is a %select{struct|union|class|enum}1 here">;
"%0 is a %select{struct|interface|union|class|enum}1 here">;
def note_odr_field : Note<"field %0 has type %1 here">;
def note_odr_missing_field : Note<"no corresponding field here">;
def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">;

View File

@ -121,5 +121,21 @@ def warn_doc_returns_attached_to_a_void_function : Warning<
"method returning void}1">,
InGroup<Documentation>, DefaultIgnore;
// \deprecated command
def warn_doc_deprecated_not_sync : Warning<
"declaration is marked with '\\deprecated' command but does not have "
"a deprecation attribute">,
InGroup<DocumentationDeprecatedSync>, DefaultIgnore;
def note_add_deprecation_attr : Note<
"add a deprecation attribute to the declaration to silence this warning">;
// verbatim block commands
def warn_verbatim_block_end_without_start : Warning<
"'\\%0' command does not terminate a verbatim text block">,
InGroup<Documentation>, DefaultIgnore;
} // end of documentation issue category
} // end of AST component

View File

@ -78,9 +78,12 @@ def note_decl_hiding_tag_type : Note<
"%1 %0 is hidden by a non-type declaration of %0 here">;
// Sema && Lex
def ext_longlong : Extension<
def ext_c99_longlong : Extension<
"'long long' is an extension when C99 mode is not enabled">,
InGroup<LongLong>;
def ext_cxx11_longlong : Extension<
"'long long' is a C++11 extension">,
InGroup<CXX11LongLong>;
def warn_cxx98_compat_longlong : Warning<
"'long long' is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;

View File

@ -11,6 +11,8 @@ let Component = "Driver" in {
def err_drv_no_such_file : Error<"no such file or directory: '%0'">;
def err_drv_unsupported_opt : Error<"unsupported option '%0'">;
def err_drv_unsupported_opt_for_target : Error<
"unsupported option '%0' for target '%1'">;
def err_drv_unsupported_option_argument : Error<
"unsupported argument '%1' to option '%0'">;
def err_drv_unknown_stdin_type : Error<
@ -91,10 +93,10 @@ def err_drv_invalid_arch_for_deployment_target : Error<
"invalid architecture '%0' for deployment target '%1'">;
def err_drv_objc_gc_arr : Error<
"cannot specify both '-fobjc-arc' and '%0'">;
def err_arc_nonfragile_abi : Error<
"-fobjc-arc is not supported with legacy abi">;
def err_arc_unsupported : Error<
"-fobjc-arc is not supported on current deployment target">;
def err_arc_unsupported_on_runtime : Error<
"-fobjc-arc is not supported on platforms using the legacy runtime">;
def err_arc_unsupported_on_toolchain : Error< // feel free to generalize this
"-fobjc-arc is not supported on versions of OS X prior to 10.6">;
def err_drv_mg_requires_m_or_mm : Error<
"option '-MG' requires '-M' or '-MM'">;
def err_drv_asan_android_requires_pie : Error<
@ -119,14 +121,10 @@ def warn_drv_unused_argument : Warning<
def warn_drv_empty_joined_argument : Warning<
"joined argument expects additional value: '%0'">,
InGroup<DiagGroup<"unused-command-line-argument">>;
def warn_drv_not_using_clang_cpp : Warning<
"not using the clang preprocessor due to user override">;
def warn_drv_not_using_clang_cxx : Warning<
"not using the clang compiler for C++ inputs">;
def warn_drv_not_using_clang_arch : Warning<
"not using the clang compiler for the '%0' architecture">;
def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
def warn_drv_deprecated_arg : Warning<
"argument '%0' is deprecated, use '%1' instead">, InGroup<Deprecated>;
def warn_drv_assuming_mfloat_abi_is : Warning<
"unknown platform, assuming -mfloat-abi=%0">;
def warn_ignoring_ftabstop_value : Warning<
@ -141,5 +139,9 @@ def warn_drv_pch_not_first_include : Warning<
def note_drv_command_failed_diag_msg : Note<
"diagnostic msg: %0">;
def err_analyzer_config_no_value : Error<
"analyzer-config option '%0' has a key but no value">;
def err_analyzer_config_multiple_values : Error<
"analyzer-config option '%0' should contain only one '='">;
}

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