Update clang to r99115.

This commit is contained in:
Roman Divacky 2010-03-21 10:50:08 +00:00
parent 4a37f65f1c
commit c0c7bca4e5
181 changed files with 5347 additions and 1742 deletions

View File

@ -18,7 +18,7 @@ $(RecursiveTargets)::
endif
test::
@ $(MAKE) -C test
@ $(MAKE) -C test
report::
@ $(MAKE) -C test report
@ -27,7 +27,8 @@ clean::
@ $(MAKE) -C test clean
tags::
$(Verb) etags `find . -type f -name \*.h | grep -v /lib/Headers | grep -v /test/` `find . -type f -name \*.cpp | grep -v /lib/Headers | grep -v /test/`
$(Verb) etags `find . -type f -name '*.h' -or -name '*.cpp' | \
grep -v /lib/Headers | grep -v /test/`
cscope.files:
find tools lib include -name '*.cpp' \

2
VER
View File

@ -1 +1 @@
1.1
1.5

669
docs/Block-ABI-Apple.txt Normal file
View File

@ -0,0 +1,669 @@
Block Implementation Specification
Copyright 2008-2010 Apple, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
0. History
2008/7/14 - created
2008/8/21 - revised, C++
2008/9/24 - add NULL isa field to __block storage
2008/10/1 - revise block layout to use a static descriptor structure
2008/10/6 - revise block layout to use an unsigned long int flags
2008/10/28 - specify use of _Block_object_assign/dispose for all "Object" types in helper functions
2008/10/30 - revise new layout to have invoke function in same place
2008/10/30 - add __weak support
2010/3/16 - rev for stret return, signature field
This document describes the Apple ABI implementation specification of Blocks.
The first shipping version of this ABI is found in Mac OS X 10.6, and shall be referred to as 10.6.ABI. Proposals have been made to enhance the blocks compiler and runtime, and these changes would form a new ABI called post-10.6.ABI if these changes were ever shipped in a product, which is purely speculative.
Since the Apple ABI references symbols from other elements of the system, any attempt to use this ABI on systems prior to SnowLeopard is undefined.
1. High Level
The ABI of blocks consist of their layout and the runtime functions required by the compiler.
A Block consists of a structure of the following form:
struct Block_literal_1 {
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor_1 {
unsigned long int reserved; // NULL
unsigned long int size; // sizeof(struct Block_literal_1)
// optional helper functions
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
void (*dispose_helper)(void *src); // IFF (1<<25)
// required post 10.6.ABI
const char *signature; // IFF (1<<30)
} *descriptor;
// imported variables
};
The following flags bits are in use thusly for a possible post.10.6.ABI:
enum {
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_STRET = (1 << 29),
BLOCK_HAS_SIGNATURE = (1 << 30),
};
In 10.6.ABI the (1<<29) was unconditionally set and ignored by the runtime - it was a transitional marker that did not get deleted after the transition. This bit is now paired with (1<<30), and represented as the pair (3<<30), for the following combinations of valid bit settings, and their meanings.
switch (flags & (3<<29)) {
case (0<<29): <unused> , error
case (1<<29): 10.6.ABI, no signature field available
case (2<<29): post-10.6.ABI, regular calling convention, presence of signature field
case (3<<29): post-10.6.ABI, stret calling convention, presence of signature field,
}
The following discussions are presented as 10.6.ABI otherwise.
Block literals may occur within functions where the structure is created in stack local memory. They may also appear as initialization expressions for Block variables of global or static local variables.
When a Block literal expression is evaluated the stack based structure is initialized as follows:
1) static descriptor structure is declared and initialized as follows:
1a) the invoke function pointer is set to a function that takes the Block structure as its first argument and the rest of the arguments (if any) to the Block and executes the Block compound statement.
1b) the size field is set to the size of the following Block literal structure.
1c) the copy_helper and dispose_helper function pointers are set to respective helper functions if they are required by the Block literal
2) a stack (or global) Block literal data structure is created and initialized as follows:
2a) the isa field is set to the address of the external _NSConcreteStackBlock, which is a block of uninitialized memory supplied in libSystem, or _NSConcreteGlobalBlock if this is a static or file level block literal.
2) The flags field is set to zero unless there are variables imported into the block that need helper functions for program level Block_copy() and Block_release() operations, in which case the (1<<25) flags bit is set.
As an example, the Block literal expression
^ { printf("hello world\n"); }
would cause to be created on a 32-bit system:
struct __block_literal_1 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_1 *);
struct __block_descriptor_1 *descriptor;
};
void __block_invoke_1(struct __block_literal_1 *_block) {
printf("hello world\n");
}
static struct __block_descriptor_1 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 };
and where the block literal appeared
struct __block_literal_1 _block_literal = {
&_NSConcreteStackBlock,
(1<<29), <uninitialized>,
__block_invoke_1,
&__block_descriptor_1
};
Blocks import other Block references, const copies of other variables, and variables marked __block. In Objective-C variables may additionally be objects.
When a Block literal expression used as the initial value of a global or static local variable it is initialized as follows:
struct __block_literal_1 __block_literal_1 = {
&_NSConcreteGlobalBlock,
(1<<28)|(1<<29), <uninitialized>,
__block_invoke_1,
&__block_descriptor_1
};
that is, a different address is provided as the first value and a particular (1<<28) bit is set in the flags field, and otherwise it is the same as for stack based Block literals. This is an optimization that can be used for any Block literal that imports no const or __block storage variables.
2. Imported Variables
Variables of "auto" storage class are imported as const copies. Variables of "__block" storage class are imported as a pointer to an enclosing data structure. Global variables are simply referenced and not considered as imported.
2.1 Imported const copy variables
Automatic storage variables not marked with __block are imported as const copies.
The simplest example is that of importing a variable of type int.
int x = 10;
void (^vv)(void) = ^{ printf("x is %d\n", x); }
x = 11;
vv();
would be compiled
struct __block_literal_2 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_2 *);
struct __block_descriptor_2 *descriptor;
const int x;
};
void __block_invoke_2(struct __block_literal_2 *_block) {
printf("x is %d\n", _block->x);
}
static struct __block_descriptor_2 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_2 = { 0, sizeof(struct __block_literal_2) };
and
struct __block_literal_2 __block_literal_2 = {
&_NSConcreteStackBlock,
(1<<29), <uninitialized>,
__block_invoke_2,
&__block_descriptor_2,
x
};
In summary, scalars, structures, unions, and function pointers are generally imported as const copies with no need for helper functions.
2.2 Imported const copy of Block reference
The first case where copy and dispose helper functions are required is for the case of when a block itself is imported. In this case both a copy_helper function and a dispose_helper function are needed. The copy_helper function is passed both the existing stack based pointer and the pointer to the new heap version and should call back into the runtime to actually do the copy operation on the imported fields within the block. The runtime functions are all described in Section 5.0 Runtime Helper Functions.
An example:
void (^existingBlock)(void) = ...;
void (^vv)(void) = ^{ existingBlock(); }
vv();
struct __block_literal_3 {
...; // existing block
};
struct __block_literal_4 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_4 *);
struct __block_literal_3 *const existingBlock;
};
void __block_invoke_4(struct __block_literal_2 *_block) {
__block->existingBlock->invoke(__block->existingBlock);
}
void __block_copy_4(struct __block_literal_4 *dst, struct __block_literal_4 *src) {
//_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
_Block_object_assign(&dst->existingBlock, src->existingBlock, BLOCK_FIELD_IS_BLOCK);
}
void __block_dispose_4(struct __block_literal_4 *src) {
// was _Block_destroy
_Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
}
static struct __block_descriptor_4 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_4 *dst, struct __block_literal_4 *src);
void (*dispose_helper)(struct __block_literal_4 *);
} __block_descriptor_4 = {
0,
sizeof(struct __block_literal_4),
__block_copy_4,
__block_dispose_4,
};
and where it is used
struct __block_literal_4 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29), <uninitialized>
__block_invoke_4,
& __block_descriptor_4
existingBlock,
};
2.2.1 Importing __attribute__((NSObject)) variables.
GCC introduces __attribute__((NSObject)) on structure pointers to mean "this is an object". This is useful because many low level data structures are declared as opaque structure pointers, e.g. CFStringRef, CFArrayRef, etc. When used from C, however, these are still really objects and are the second case where that requires copy and dispose helper functions to be generated. The copy helper functions generated by the compiler should use the _Block_object_assign runtime helper function and in the dispose helper the _Block_object_dispose runtime helper function should be called.
For example, block xyzzy in the following
struct Opaque *__attribute__((NSObject)) objectPointer = ...;
...
void (^xyzzy)(void) = ^{ CFPrint(objectPointer); };
would have helper functions
void __block_copy_xyzzy(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
_Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
}
void __block_dispose_xyzzy(struct __block_literal_5 *src) {
_Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
}
generated.
2.3 Imported __block marked variables.
2.3.1 Layout of __block marked variables
The compiler must embed variables that are marked __block in a specialized structure of the form:
struct _block_byref_xxxx {
void *isa;
struct Block_byref *forwarding;
int flags; //refcount;
int size;
typeof(marked_variable) marked_variable;
};
Variables of certain types require helper functions for when Block_copy() and Block_release() are performed upon a referencing Block. At the "C" level only variables that are of type Block or ones that have __attribute__((NSObject)) marked require helper functions. In Objective-C objects require helper functions and in C++ stack based objects require helper functions. Variables that require helper functions use the form:
struct _block_byref_xxxx {
void *isa;
struct _block_byref_xxxx *forwarding;
int flags; //refcount;
int size;
// helper functions called via Block_copy() and Block_release()
void (*byref_keep)(void *dst, void *src);
void (*byref_dispose)(void *);
typeof(marked_variable) marked_variable;
};
The structure is initialized such that
a) the forwarding pointer is set to the beginning of its enclosing structure,
b) the size field is initialized to the total size of the enclosing structure,
c) the flags field is set to either 0 if no helper functions are needed or (1<<25) if they are,
d) the helper functions are initialized (if present)
e) the variable itself is set to its initial value.
f) the isa field is set to NULL
2.3.2 Access to __block variables from within its lexical scope.
In order to "move" the variable to the heap upon a copy_helper operation the compiler must rewrite access to such a variable to be indirect through the structures forwarding pointer. For example:
int __block i = 10;
i = 11;
would be rewritten to be:
struct _block_byref_i {
void *isa;
struct _block_byref_i *forwarding;
int flags; //refcount;
int size;
int captured_i;
} i = { NULL, &i, 0, sizeof(struct _block_byref_i), 11 };
i.forwarding->captured_i = 11;
In the case of a Block reference variable being marked __block the helper code generated must use the _Block_object_assign and _Block_object_dispose routines supplied by the runtime to make the copies. For example:
__block void (voidBlock)(void) = blockA;
voidBlock = blockB;
would translate into
struct _block_byref_voidBlock {
void *isa;
struct _block_byref_voidBlock *forwarding;
int flags; //refcount;
int size;
void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
void (*byref_dispose)(struct _block_byref_voidBlock *);
void (^captured_voidBlock)(void);
};
void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
//_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
_Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
}
void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
//_Block_destroy(param->captured_voidBlock, 0);
_Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
and
struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
.byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
.captured_voidBlock=blockA };
voidBlock.forwarding->captured_voidBlock = blockB;
2.3.3 Importing __block variables into Blocks
A Block that uses a __block variable in its compound statement body must import the variable and emit copy_helper and dispose_helper helper functions that, in turn, call back into the runtime to actually copy or release the byref data block using the functions _Block_object_assign and _Block_object_dispose.
For example:
int __block i = 2;
functioncall(^{ i = 10; });
would translate to
struct _block_byref_i {
void *isa; // set to NULL
struct _block_byref_voidBlock *forwarding;
int flags; //refcount;
int size;
void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
void (*byref_dispose)(struct _block_byref_i *);
int captured_i;
};
struct __block_literal_5 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_5 *);
struct __block_descriptor_5 *descriptor;
struct _block_byref_i *i_holder;
};
void __block_invoke_5(struct __block_literal_5 *_block) {
_block->forwarding->captured_i = 10;
}
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
//_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
_Block_object_assign(&dst->captured_i, src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}
void __block_dispose_5(struct __block_literal_5 *src) {
//_Block_byref_release(src->captured_i);
_Block_object_dispose(src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}
static struct __block_descriptor_5 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
void (*dispose_helper)(struct __block_literal_5 *);
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };
and
struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
struct __block_literal_5 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29), <uninitialized>,
__block_invoke_5,
&__block_descriptor_5,
2,
};
2.3.4 Importing __attribute__((NSObject)) __block variables
A __block variable that is also marked __attribute__((NSObject)) should have byref_keep and byref_dispose helper functions that use _Block_object_assign and _Block_object_dispose.
2.3.5 __block escapes
Because Blocks referencing __block variables may have Block_copy() performed upon them the underlying storage for the variables may move to the heap. In Objective-C Garbage Collection Only compilation environments the heap used is the garbage collected one and no further action is required. Otherwise the compiler must issue a call to potentially release any heap storage for __block variables at all escapes or terminations of their scope.
2.3.6 Nesting
Blocks may contain Block literal expressions. Any variables used within inner blocks are imported into all enclosing Block scopes even if the variables are not used. This includes const imports as well as __block variables.
3. Objective C Extensions to Blocks
3.1 Importing Objects
Objects should be treated as __attribute__((NSObject)) variables; all copy_helper, dispose_helper, byref_keep, and byref_dispose helper functions should use _Block_object_assign and _Block_object_dispose. There should be no code generated that uses -retain or -release methods.
3.2 Blocks as Objects
The compiler will treat Blocks as objects when synthesizing property setters and getters, will characterize them as objects when generating garbage collection strong and weak layout information in the same manner as objects, and will issue strong and weak write-barrier assignments in the same manner as objects.
3.3 __weak __block Support
Objective-C (and Objective-C++) support the __weak attribute on __block variables. Under normal circumstances the compiler uses the Objective-C runtime helper support functions objc_assign_weak and objc_read_weak. Both should continue to be used for all reads and writes of __weak __block variables:
objc_read_weak(&block->byref_i->forwarding->i)
The __weak variable is stored in a _block_byref_xxxx structure and the Block has copy and dispose helpers for this structure that call:
_Block_object_assign(&dest->_block_byref_i, src-> _block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
and
_Block_object_dispose(src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
In turn, the block_byref copy support helpers distinguish between whether the __block variable is a Block or not and should either call:
_Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_OBJECT | BLOCK_BYREF_CALLER);
for something declared as an object or
_Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
for something declared as a Block.
A full example follows:
__block __weak id obj = <initialization expression>;
functioncall(^{ [obj somemessage]; });
would translate to
struct _block_byref_obj {
void *isa; // uninitialized
struct _block_byref_obj *forwarding;
int flags; //refcount;
int size;
void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
void (*byref_dispose)(struct _block_byref_i *);
int captured_obj;
};
void _block_byref_obj_keep(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
//_Block_copy_assign(&dst->captured_obj, src->captured_obj, 0);
_Block_object_assign(&dst->captured_obj, src->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
}
void _block_byref_obj_dispose(struct _block_byref_voidBlock *param) {
//_Block_destroy(param->captured_obj, 0);
_Block_object_dispose(param->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
};
for the block byref part and
struct __block_literal_5 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_5 *);
struct __block_descriptor_5 *descriptor;
struct _block_byref_obj *byref_obj;
};
void __block_invoke_5(struct __block_literal_5 *_block) {
[objc_read_weak(&_block->byref_obj->forwarding->captured_obj) somemessage];
}
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
//_Block_byref_assign_copy(&dst->byref_obj, src->byref_obj);
_Block_object_assign(&dst->byref_obj, src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
}
void __block_dispose_5(struct __block_literal_5 *src) {
//_Block_byref_release(src->byref_obj);
_Block_object_dispose(src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
}
static struct __block_descriptor_5 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
void (*dispose_helper)(struct __block_literal_5 *);
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5), __block_copy_5, __block_dispose_5 };
and within the compound statement:
struct _block_byref_obj obj = {( .forwarding=&obj, .flags=(1<<25), .size=sizeof(struct _block_byref_obj),
.byref_keep=_block_byref_obj_keep, .byref_dispose=_block_byref_obj_dispose,
.captured_obj = <initialization expression> )};
struct __block_literal_5 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29), <uninitialized>,
__block_invoke_5,
&__block_descriptor_5,
&obj, // a reference to the on-stack structure containing "captured_obj"
};
functioncall(_block_literal->invoke(&_block_literal));
4.0 C++ Support
Within a block stack based C++ objects are copied as const copies using the const copy constructor. It is an error if a stack based C++ object is used within a block if it does not have a const copy constructor. In addition both copy and destroy helper routines must be synthesized for the block to support the Block_copy() operation, and the flags work marked with the (1<<26) bit in addition to the (1<<25) bit. The copy helper should call the constructor using appropriate offsets of the variable within the supplied stack based block source and heap based destination for all const constructed copies, and similarly should call the destructor in the destroy routine.
As an example, suppose a C++ class FOO existed with a const copy constructor. Within a code block a stack version of a FOO object is declared and used within a Block literal expression:
{
FOO foo;
void (^block)(void) = ^{ printf("%d\n", foo.value()); };
}
The compiler would synthesize
struct __block_literal_10 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_10 *);
struct __block_descriptor_10 *descriptor;
const FOO foo;
};
void __block_invoke_10(struct __block_literal_10 *_block) {
printf("%d\n", _block->foo.value());
}
void __block_literal_10(struct __block_literal_10 *dst, struct __block_literal_10 *src) {
comp_ctor(&dst->foo, &src->foo);
}
void __block_dispose_10(struct __block_literal_10 *src) {
comp_dtor(&src->foo);
}
static struct __block_descriptor_10 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_10 *dst, struct __block_literal_10 *src);
void (*dispose_helper)(struct __block_literal_10 *);
} __block_descriptor_10 = { 0, sizeof(struct __block_literal_10), __block_copy_10, __block_dispose_10 };
and the code would be:
{
FOO foo;
comp_ctor(&foo); // default constructor
struct __block_literal_10 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<26)|(1<<29), <uninitialized>,
__block_invoke_10,
&__block_descriptor_10,
};
comp_ctor(&_block_literal->foo, &foo); // const copy into stack version
struct __block_literal_10 &block = &_block_literal; // assign literal to block variable
block->invoke(block); // invoke block
comp_dtor(&_block_literal->foo); // destroy stack version of const block copy
comp_dtor(&foo); // destroy original version
}
C++ objects stored in __block storage start out on the stack in a block_byref data structure as do other variables. Such objects (if not const objects) must support a regular copy constructor. The block_byref data structure will have copy and destroy helper routines synthesized by the compiler. The copy helper will have code created to perform the copy constructor based on the initial stack block_byref data structure, and will also set the (1<<26) bit in addition to the (1<<25) bit. The destroy helper will have code to do the destructor on the object stored within the supplied block_byref heap data structure.
To support member variable and function access the compiler will synthesize a const pointer to a block version of the this pointer.
5.0 Runtime Helper Functions
The runtime helper functions are described in /usr/local/include/Block_private.h. To summarize their use, a block requires copy/dispose helpers if it imports any block variables, __block storage variables, __attribute__((NSObject)) variables, or C++ const copied objects with constructor/destructors. The (1<<26) bit is set and functions are generated.
The block copy helper function should, for each of the variables of the type mentioned above, call
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<appropo>);
in the copy helper and
_Block_object_dispose(->target, BLOCK_FIELD_<appropo>);
in the dispose helper where
<appropo> is
enum {
BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
BLOCK_FIELD_IS_BLOCK = 7, // a block variable
BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
BLOCK_FIELD_IS_WEAK = 16, // declared __weak
BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
};
and of course the CTORs/DTORs for const copied C++ objects.
The block_byref data structure similarly requires copy/dispose helpers for block variables, __attribute__((NSObject)) variables, or C++ const copied objects with constructor/destructors, and again the (1<<26) bit is set and functions are generated in the same manner.
Under ObjC we allow __weak as an attribute on __block variables, and this causes the addition of BLOCK_FIELD_IS_WEAK orred onto the BLOCK_FIELD_IS_BYREF flag when copying the block_byref structure in the block copy helper, and onto the BLOCK_FIELD_<appropo> field within the block_byref copy/dispose helper calls.
The prototypes, and summary, of the helper functions are
/* Certain field types require runtime assistance when being copied to the heap. The following function is used
to copy fields of types: blocks, pointers to byref structures, and objects (including __attribute__((NSObject)) pointers.
BLOCK_FIELD_IS_WEAK is orthogonal to the other choices which are mutually exclusive.
Only in a Block copy helper will one see BLOCK_FIELD_IS_BYREF.
*/
void _Block_object_assign(void *destAddr, const void *object, const int flags);
/* Similarly a compiler generated dispose helper needs to call back for each field of the byref data structure.
(Currently the implementation only packs one field into the byref structure but in principle there could be more).
The same flags used in the copy helper should be used for each call generated to this function:
*/
void _Block_object_dispose(const void *object, const int flags);
The following functions have been used and will continue to be supported until new compiler support is complete.
// Obsolete functions.
// Copy helper callback for copying a block imported into a Block
// Called by copy_helper helper functions synthesized by the compiler.
// The address in the destination block of an imported Block is provided as the first argument
// and the value of the existing imported Block is the second.
// Use: _Block_object_assign(dest, src, BLOCK_FIELD_IS_BLOCK {| BLOCK_FIELD_IS_WEAK});
void _Block_copy_assign(struct Block_basic **dest, const struct Block_basic *src, const int flags);
// Destroy helper callback for releasing Blocks imported into a Block
// Called by dispose_helper helper functions synthesized by the compiler.
// The value of the imported Block variable is passed back.
// Use: _Block_object_dispose(src, BLOCK_FIELD_IS_BLOCK {| BLOCK_FIELD_IS_WEAK});
void _Block_destroy(const struct Block_basic *src, const int flags);
// Byref data block copy helper callback
// Called by block copy helpers when copying __block structures
// Use: _Block_object_assign(dest, src, BLOCK_FIELD_IS_BYREF {| BLOCK_FIELD_IS_WEAK});
void _Block_byref_assign_copy(struct Block_byref **destp, struct Block_byref *src);
// Byref data block release helper callback
// Called by block release helpers when releasing a Block
// Called at escape points in scope where __block variables live (under non-GC-only conditions)
// Use: _Block_object_dispose(src, BLOCK_FIELD_IS_BYREF {| BLOCK_FIELD_IS_WEAK});
void §(struct Block_byref *shared_struct);

View File

@ -315,7 +315,7 @@ enabled. clang does not yet fully implement this feature.</p>
<p>The syntax and high level language feature description is in <a
href="BlockLanguageSpec.txt">BlockLanguageSpec.txt</a>. Implementation and ABI
details for the clang implementation are in <a
href="BlockImplementation.txt">BlockImplementation.txt</a>.</p>
href="Block-ABI-Apple.txt">Block-ABI-Apple.txt</a>.</p>
<p>Query for this feature with __has_feature(blocks).</p>

View File

@ -796,6 +796,13 @@ ask on the mailing list about how you can help.</p>
<p>Note that released Clang compilers will refuse to even try to use clang to compile C++ code unless you pass the <tt>-ccc-clang-cxx</tt> option to the driver. To turn on Clang's C++ support, please pass that flag. Clang compilers built from the Subversion trunk enable C++ support by default, and do not require the <tt>-ccc-clang-cxx</tt> flag.</p>
<p>Clang strives to strictly conform to the C++ standard. That means
it will reject invalid C++ code that another compiler may accept. If
Clang reports errors in your code, please check
the <a href="http://clang.llvm.org/cxx_compatibility.html">C++
Compatibility</a> page to see whether they are C++-conformance bugs
and how you can fix them.</p>
<!-- ======================================================================= -->
<h2 id="objcxx">Objective C++ Language Features</h2>
<!-- ======================================================================= -->

View File

@ -728,7 +728,8 @@ enum CXCursorKind {
CXCursor_InvalidFile = 70,
CXCursor_NoDeclFound = 71,
CXCursor_NotImplemented = 72,
CXCursor_LastInvalid = 72,
CXCursor_InvalidCode = 73,
CXCursor_LastInvalid = CXCursor_InvalidCode,
/* Expressions */
CXCursor_FirstExpr = 100,
@ -796,7 +797,14 @@ enum CXCursorKind {
CXCursor_IBActionAttr = 401,
CXCursor_IBOutletAttr = 402,
CXCursor_LastAttr = CXCursor_IBOutletAttr
CXCursor_LastAttr = CXCursor_IBOutletAttr,
/* Preprocessing */
CXCursor_PreprocessingDirective = 500,
CXCursor_MacroDefinition = 501,
CXCursor_MacroInstantiation = 502,
CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective,
CXCursor_LastPreprocessing = CXCursor_MacroInstantiation
};
/**
@ -888,6 +896,12 @@ CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind);
*/
CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind);
/***
* \brief Determine whether the given cursor represents a preprocessing
* element, such as a preprocessor directive or macro instantiation.
*/
CINDEX_LINKAGE unsigned clang_isPreprocessing(enum CXCursorKind);
/***
* \brief Determine whether the given cursor represents a currently
* unexposed piece of the AST (e.g., CXCursor_UnexposedStmt).

View File

@ -259,19 +259,11 @@ class ASTContext {
/// this ASTContext object.
LangOptions LangOpts;
/// \brief Whether we have already loaded comment source ranges from an
/// external source.
bool LoadedExternalComments;
/// MallocAlloc/BumpAlloc - The allocator objects used to create AST objects.
bool FreeMemory;
llvm::MallocAllocator MallocAlloc;
llvm::BumpPtrAllocator BumpAlloc;
/// \brief Mapping from declarations to their comments, once we have
/// already looked up the comment associated with a given declaration.
llvm::DenseMap<const Decl *, std::string> DeclComments;
public:
const TargetInfo &Target;
IdentifierTable &Idents;
@ -287,10 +279,6 @@ public:
QualType ObjCClassRedefinitionType;
QualType ObjCSelRedefinitionType;
/// \brief Source ranges for all of the comments in the source file,
/// sorted in order of appearance in the translation unit.
std::vector<SourceRange> Comments;
SourceManager& getSourceManager() { return SourceMgr; }
const SourceManager& getSourceManager() const { return SourceMgr; }
void *Allocate(unsigned Size, unsigned Align = 8) {
@ -357,8 +345,6 @@ public:
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
const char *getCommentForDecl(const Decl *D);
// Builtin Types.
CanQualType VoidTy;
CanQualType BoolTy;
@ -1161,6 +1147,8 @@ public:
/// Compatibility predicates used to check assignment expressions.
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
bool typesAreBlockPointerCompatible(QualType, QualType);
bool isObjCIdType(QualType T) const {
return T == ObjCIdTypedefType;
}
@ -1179,13 +1167,16 @@ public:
const ObjCObjectPointerType *RHSOPT);
bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
const ObjCInterfaceType *RHS);
bool canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT);
bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
QualType areCommonBaseCompatible(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT);
// Functions for calculating composite types
QualType mergeTypes(QualType, QualType);
QualType mergeFunctionTypes(QualType, QualType);
QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false);
QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false);
/// UsualArithmeticConversionsType - handles the various conversions
/// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9)
@ -1312,10 +1303,10 @@ static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
/// this ever changes, this operator will have to be changed, too.)
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
/// @code
/// // Default alignment (16)
/// // Default alignment (8)
/// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments);
/// // Specific alignment
/// IntegerLiteral *Ex2 = new (Context, 8) IntegerLiteral(arguments);
/// IntegerLiteral *Ex2 = new (Context, 4) IntegerLiteral(arguments);
/// @endcode
/// Please note that you cannot use delete on the pointer; it must be
/// deallocated using an explicit destructor call followed by
@ -1346,10 +1337,10 @@ inline void operator delete(void *Ptr, clang::ASTContext &C, size_t)
/// null on error.
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
/// @code
/// // Default alignment (16)
/// // Default alignment (8)
/// char *data = new (Context) char[10];
/// // Specific alignment
/// char *data = new (Context, 8) char[10];
/// char *data = new (Context, 4) char[10];
/// @endcode
/// Please note that you cannot use delete on the pointer; it must be
/// deallocated using an explicit destructor call followed by
@ -1361,7 +1352,7 @@ inline void operator delete(void *Ptr, clang::ASTContext &C, size_t)
/// allocator supports it).
/// @return The allocated memory. Could be NULL.
inline void *operator new[](size_t Bytes, clang::ASTContext& C,
size_t Alignment = 16) throw () {
size_t Alignment = 8) throw () {
return C.Allocate(Bytes, Alignment);
}

View File

@ -150,7 +150,6 @@ public:
LV_InvalidExpression,
LV_MemberFunction,
LV_SubObjCPropertySetting,
LV_SubObjCPropertyGetterSetting,
LV_ClassTemporary
};
isLvalueResult isLvalue(ASTContext &Ctx) const;
@ -182,7 +181,6 @@ public:
MLV_NoSetterProperty,
MLV_MemberFunction,
MLV_SubObjCPropertySetting,
MLV_SubObjCPropertyGetterSetting,
MLV_ClassTemporary
};
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,

View File

@ -58,14 +58,6 @@ public:
virtual ~ExternalASTSource();
/// \brief Reads the source ranges that correspond to comments from
/// an external AST source.
///
/// \param Comments the contents of this vector will be
/// replaced with the sorted set of source ranges corresponding to
/// comments in the source code.
virtual void ReadComments(std::vector<SourceRange> &Comments) = 0;
/// \brief Resolve a type ID into a type, potentially building a new
/// type.
virtual QualType GetType(uint32_t ID) = 0;

View File

@ -126,12 +126,12 @@ public:
// Only allow allocation of Stmts using the allocator in ASTContext
// or by doing a placement new.
void* operator new(size_t bytes, ASTContext& C,
unsigned alignment = 16) throw() {
unsigned alignment = 8) throw() {
return ::operator new(bytes, C, alignment);
}
void* operator new(size_t bytes, ASTContext* C,
unsigned alignment = 16) throw() {
unsigned alignment = 8) throw() {
return ::operator new(bytes, *C, alignment);
}

View File

@ -94,6 +94,7 @@ public:
NamedDecl *getDecl() const { return ir->getDecl(); }
AccessSpecifier getAccess() const { return ir->getAccess(); }
DeclAccessPair getPair() const { return *ir; }
NamedDecl *operator*() const { return getDecl(); }

View File

@ -293,4 +293,28 @@ BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_pcmpeqq, "V2LLiV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16ci", "")
// SSE 4.2
BUILTIN(__builtin_ia32_pcmpistrm128, "V16cV16cV16cc", "")
BUILTIN(__builtin_ia32_pcmpistri128, "iV16cV16cc", "")
BUILTIN(__builtin_ia32_pcmpestrm128, "V16cV16ciV16cic", "")
BUILTIN(__builtin_ia32_pcmpestri128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpistria128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpistric128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpistrio128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpistris128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpistriz128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpestria128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpestric128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpestrio128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpestris128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpestriz128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpgtq, "V2LLiV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_crc32qi, "iic", "")
BUILTIN(__builtin_ia32_crc32hi, "iis", "")
BUILTIN(__builtin_ia32_crc32si, "iii", "")
BUILTIN(__builtin_ia32_crc32di, "LLiLLiLLi", "")
#undef BUILTIN

View File

@ -65,9 +65,6 @@ def err_target_invalid_feature : Error<"invalid target feature '%0'">;
// Source manager
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
def err_file_size_changed : Error<
"size of file '%0' changed since it was first processed (from %1 to %2)">,
DefaultFatal;
def err_file_modified : Error<
"file '%0' modified since it was first processed">, DefaultFatal;

View File

@ -64,6 +64,8 @@ def err_drv_invalid_remap_file : Error<
"invalid option '%0' not of the form <from-file>;<to-file>">;
def err_drv_invalid_gcc_output_type : Error<
"invalid output type '%0' for use with gcc tool">;
def err_drv_cc_print_options_failure : Error<
"unable to open CC_PRINT_OPTIONS file: %0">;
def warn_drv_input_file_unused : Warning<
"%0: '%1' input unused when '%2' is present">;

View File

@ -51,12 +51,16 @@ def err_fe_unable_to_read_pch_file : Error<
"unable to read PCH file: '%0'">;
def err_fe_not_a_pch_file : Error<
"input is not a PCH file: '%0'">;
def err_fe_pch_malformed : Error<
"malformed or corrupted PCH file: '%0'">, DefaultFatal;
def err_fe_pch_malformed_block : Error<
"malformed block record in PCH file: '%0'">;
"malformed block record in PCH file: '%0'">, DefaultFatal;
def err_fe_pch_error_at_end_block : Error<
"error at end of module block in PCH file: '%0'">;
"error at end of module block in PCH file: '%0'">, DefaultFatal;
def err_fe_unable_to_open_output : Error<
"unable to open output file '%0': '%1'">;
def err_fe_unable_to_open_logfile : Error<
"unable to open logfile file '%0': '%1'">;
def err_fe_pth_file_has_no_source_header : Error<
"PTH file '%0' does not designate an original source header file for -include-pth">;
def warn_fe_macro_contains_embedded_newline : Warning<

View File

@ -73,7 +73,7 @@ def : DiagGroup<"redundant-decls">;
def ReturnType : DiagGroup<"return-type">;
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
def : DiagGroup<"sequence-point">;
def : DiagGroup<"shadow">;
def Shadow : DiagGroup<"shadow">;
def : DiagGroup<"shorten-64-to-32">;
def SignCompare : DiagGroup<"sign-compare">;
def : DiagGroup<"synth">;

View File

@ -107,7 +107,15 @@ def warn_use_out_of_scope_declaration : Warning<
"use of out-of-scope declaration of %0">;
def err_inline_non_function : Error<
"'inline' can only appear on functions">;
def warn_decl_shadow :
Warning<"declaration shadows a %select{"
"local variable|"
"variable in %2|"
"static data member of %2|"
"field of %2}1">,
InGroup<Shadow>, DefaultIgnore;
// C++ using declarations
def err_using_requires_qualname : Error<
"using declaration requires a qualified name">;
@ -1529,8 +1537,7 @@ def err_forward_ref_enum : Error<
"ISO C++ forbids forward references to 'enum' types">;
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
def err_misplaced_ivar : Error<"ivar may be placed in a class extension "
"in non-fragile-abi2 mode only">;
def err_misplaced_ivar : Error<"ivars may not be placed in categories">;
def ext_enum_value_not_int : Extension<
"ISO C restricts enumerator values to range of 'int' (%0 is too "
"%select{small|large}1)">;
@ -1881,16 +1888,16 @@ def err_stmtexpr_file_scope : Error<
"statement expression not allowed at file scope">;
def warn_mixed_sign_comparison : Warning<
"comparison of integers of different signs: %0 and %1">,
InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
InGroup<SignCompare>, DefaultIgnore;
def warn_mixed_sign_conditional : Warning<
"operands of ? are integers of different signs: %0 and %1">,
InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
InGroup<SignCompare>, DefaultIgnore;
def warn_lunsigned_always_true_comparison : Warning<
"comparison of unsigned expression %0 is always %1">,
InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
InGroup<SignCompare>, DefaultIgnore;
def warn_runsigned_always_true_comparison : Warning<
"comparison of %0 unsigned expression is always %1">,
InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
InGroup<SignCompare>, DefaultIgnore;
def err_invalid_this_use : Error<
"invalid use of 'this' outside of a nonstatic member function">;
@ -1944,11 +1951,7 @@ def ext_integer_complement_complex : Extension<
def error_nosetter_property_assignment : Error<
"setter method is needed to assign to object using property" " assignment syntax">;
def error_no_subobject_property_setting : Error<
"cannot assign to a sub-structure of an ivar using property"
" assignment syntax">;
def error_no_subobject_property_getter_setting : Error<
"cannot assign to a sub-structure returned via a getter using property"
" assignment syntax">;
"expression is not assignable using property assignment syntax">;
def ext_freestanding_complex : Extension<
"complex numbers are an extension in a freestanding C99 implementation">;

View File

@ -200,19 +200,19 @@ public:
FullSourceLoc getInstantiationLoc() const;
FullSourceLoc getSpellingLoc() const;
unsigned getInstantiationLineNumber() const;
unsigned getInstantiationColumnNumber() const;
unsigned getInstantiationLineNumber(bool *Invalid = 0) const;
unsigned getInstantiationColumnNumber(bool *Invalid = 0) const;
unsigned getSpellingLineNumber() const;
unsigned getSpellingColumnNumber() const;
unsigned getSpellingLineNumber(bool *Invalid = 0) const;
unsigned getSpellingColumnNumber(bool *Invalid = 0) const;
const char *getCharacterData() const;
const char *getCharacterData(bool *Invalid = 0) const;
const llvm::MemoryBuffer* getBuffer() const;
const llvm::MemoryBuffer* getBuffer(bool *Invalid = 0) const;
/// getBufferData - Return a StringRef to the source buffer data for the
/// specified FileID.
llvm::StringRef getBufferData() const;
llvm::StringRef getBufferData(bool *Invalid = 0) const;
/// getDecomposedLoc - Decompose the specified location into a raw FileID +
/// Offset pair. The first element is the FileID, the second is the

View File

@ -17,6 +17,7 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/Allocator.h"
#include "llvm/System/DataTypes.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/DenseMap.h"
#include <vector>
@ -54,7 +55,8 @@ namespace SrcMgr {
class ContentCache {
/// Buffer - The actual buffer containing the characters from the input
/// file. This is owned by the ContentCache object.
mutable const llvm::MemoryBuffer *Buffer;
/// The bit indicates whether the buffer is invalid.
mutable llvm::PointerIntPair<const llvm::MemoryBuffer *, 1, bool> Buffer;
public:
/// Reference to the file entry. This reference does not own
@ -92,8 +94,9 @@ namespace SrcMgr {
unsigned getSizeBytesMapped() const;
void setBuffer(const llvm::MemoryBuffer *B) {
assert(!Buffer && "MemoryBuffer already set.");
Buffer = B;
assert(!Buffer.getPointer() && "MemoryBuffer already set.");
Buffer.setPointer(B);
Buffer.setInt(false);
}
/// \brief Replace the existing buffer (which will be deleted)
@ -101,17 +104,19 @@ namespace SrcMgr {
void replaceBuffer(const llvm::MemoryBuffer *B);
ContentCache(const FileEntry *Ent = 0)
: Buffer(0), Entry(Ent), SourceLineCache(0), NumLines(0) {}
: Buffer(0, false), Entry(Ent), SourceLineCache(0), NumLines(0) {}
~ContentCache();
/// The copy ctor does not allow copies where source object has either
/// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
/// is not transfered, so this is a logical error.
ContentCache(const ContentCache &RHS) : Buffer(0), SourceLineCache(0) {
ContentCache(const ContentCache &RHS)
: Buffer(0, false), SourceLineCache(0)
{
Entry = RHS.Entry;
assert (RHS.Buffer == 0 && RHS.SourceLineCache == 0
assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0
&& "Passed ContentCache object cannot own a buffer.");
NumLines = RHS.NumLines;

View File

@ -22,7 +22,7 @@
// FIXME: Updates to this file must also update CMakeLists.txt and VER.
/// \brief Clang minor version
#define CLANG_VERSION_MINOR 1
#define CLANG_VERSION_MINOR 5
/// \brief Clang patchlevel version
// #define CLANG_VERSION_PATCHLEVEL 1

View File

@ -17,13 +17,15 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/PathSensitive/GRState.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/ImmutableSet.h"
#include <list>
namespace clang {
@ -45,7 +47,7 @@ class ParentMap;
// Interface for individual bug reports.
//===----------------------------------------------------------------------===//
class BugReporterVisitor {
class BugReporterVisitor : public llvm::FoldingSetNode {
public:
virtual ~BugReporterVisitor();
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
@ -53,6 +55,7 @@ public:
BugReporterContext& BRC) = 0;
virtual bool isOwnedByReporterContext() { return true; }
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
};
// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
@ -385,16 +388,18 @@ public:
class BugReporterContext {
GRBugReporter &BR;
std::vector<BugReporterVisitor*> Callbacks;
// Not the most efficient data structure, but we use an ImmutableList for the
// Callbacks because it is safe to make additions to list during iteration.
llvm::ImmutableList<BugReporterVisitor*>::Factory F;
llvm::ImmutableList<BugReporterVisitor*> Callbacks;
llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
public:
BugReporterContext(GRBugReporter& br) : BR(br) {}
BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.GetEmptyList()) {}
virtual ~BugReporterContext();
void addVisitor(BugReporterVisitor* visitor) {
if (visitor) Callbacks.push_back(visitor);
}
void addVisitor(BugReporterVisitor* visitor);
typedef std::vector<BugReporterVisitor*>::iterator visitor_iterator;
typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
visitor_iterator visitor_begin() { return Callbacks.begin(); }
visitor_iterator visitor_end() { return Callbacks.end(); }
@ -467,6 +472,7 @@ void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
const ExplodedNode *N);
void registerNilReceiverVisitor(BugReporterContext &BRC);
} // end namespace clang::bugreporter

View File

@ -453,6 +453,7 @@ public:
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
public:

View File

@ -144,6 +144,7 @@ public:
}
virtual Store RemoveDeadBindings(Store store, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;

View File

@ -30,6 +30,9 @@ public:
};
unsigned AsmVerbose : 1; /// -dA, -fverbose-asm.
unsigned CXAAtExit : 1; /// Use __cxa_atexit for calling destructors.
unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
/// aliases to base ctors when possible.
unsigned DebugInfo : 1; /// Should generate deubg info (-g).
unsigned DisableFPElim : 1; /// Set when -fomit-frame-pointer is enabled.
unsigned DisableLLVMOpts : 1; /// Don't run any optimizations, for use in
@ -53,8 +56,6 @@ public:
unsigned UnwindTables : 1; /// Emit unwind tables.
unsigned VerifyModule : 1; /// Control whether the module should be run
/// through the LLVM Verifier.
unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
/// aliases to base ctors when possible.
/// The code model to use (-mcmodel).
std::string CodeModel;
@ -86,6 +87,8 @@ public:
public:
CodeGenOptions() {
AsmVerbose = 0;
CXAAtExit = 1;
CXXCtorDtorAliases = 0;
DebugInfo = 0;
DisableFPElim = 0;
DisableLLVMOpts = 0;
@ -103,7 +106,6 @@ public:
UnrollLoops = 0;
UnwindTables = 0;
VerifyModule = 1;
CXXCtorDtorAliases = 0;
Inlining = NoInlining;
RelocationModel = "pic";

View File

@ -227,8 +227,6 @@ def code_completion_macros : Flag<"-code-completion-macros">,
HelpText<"Include macros in code-completion results">;
def disable_free : Flag<"-disable-free">,
HelpText<"Disable freeing of memory on exit">;
def empty_input_only : Flag<"-empty-input-only">,
HelpText<"Force running on an empty input file">;
def help : Flag<"-help">,
HelpText<"Print this help text">;
def _help : Flag<"--help">, Alias<help>;
@ -262,6 +260,8 @@ def analyze : Flag<"-analyze">,
HelpText<"Run static analysis engine">;
def dump_tokens : Flag<"-dump-tokens">,
HelpText<"Run preprocessor, dump internal rep of tokens">;
def init_only : Flag<"-init-only">,
HelpText<"Only execute frontend initialization">;
def parse_noop : Flag<"-parse-noop">,
HelpText<"Run parser with noop callbacks (for timings)">;
def fsyntax_only : Flag<"-fsyntax-only">,
@ -355,10 +355,12 @@ def fno_elide_constructors : Flag<"-fno-elide-constructors">,
HelpText<"Disable C++ copy constructor elision">;
def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">,
HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">;
def fno_signed_char : Flag<"-fno-signed-char">,
HelpText<"Char is unsigned">;
def fno_operator_names : Flag<"-fno-operator-names">,
HelpText<"Do not treat C++ operator name keywords as synonyms for operators">;
def fno_signed_char : Flag<"-fno-signed-char">,
HelpText<"Char is unsigned">;
def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">,
HelpText<"Don't use __cxa_atexit for calling destructors">;
def fconstant_string_class : Separate<"-fconstant-string-class">,
MetaVarName<"<class name>">,
HelpText<"Specify the class to use for constant Objective-C string objects.">;
@ -448,7 +450,9 @@ def U : JoinedOrSeparate<"-U">, MetaVarName<"<macro>">,
HelpText<"Undefine the specified macro">;
def undef : Flag<"-undef">, MetaVarName<"<macro>">,
HelpText<"undef all system defines">;
def detailed_preprocessing_record : Flag<"-detailed-preprocessing-record">,
HelpText<"include a detailed record of preprocessing actions">;
//===----------------------------------------------------------------------===//
// Preprocessed Output Options
//===----------------------------------------------------------------------===//

View File

@ -83,6 +83,9 @@ public:
/// Name to use when calling the generic gcc.
std::string CCCGenericGCCName;
/// The file to log CC_PRINT_OPTIONS output to, if enabled.
const char *CCPrintOptionsFilename;
/// Whether the driver should follow g++ like behavior.
unsigned CCCIsCXX : 1;
@ -92,6 +95,10 @@ public:
/// Only print tool bindings, don't build any jobs.
unsigned CCCPrintBindings : 1;
/// Set CC_PRINT_OPTIONS mode, which is like -v but logs the commands to
/// CCPrintOptionsFilename or to stderr.
unsigned CCPrintOptions : 1;
private:
/// Whether to check that input files exist when constructing compilation
/// jobs.

View File

@ -229,6 +229,7 @@ def exported__symbols__list : Separate<"-exported_symbols_list">;
def e : JoinedOrSeparate<"-e">;
def fPIC : Flag<"-fPIC">, Group<f_Group>;
def fPIE : Flag<"-fPIE">, Group<f_Group>;
def faccess_control : Flag<"-faccess-control">, Group<f_Group>;
def fapple_kext : Flag<"-fapple-kext">, Group<f_Group>;
def fasm_blocks : Flag<"-fasm-blocks">, Group<clang_ignored_f_Group>;
def fassume_sane_operator_new : Flag<"-fassume-sane-operator-new">, Group<f_Group>;
@ -262,6 +263,7 @@ def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>;
def fencoding_EQ : Joined<"-fencoding=">, Group<f_Group>;
def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
def fhosted : Flag<"-fhosted">, Group<f_Group>;
def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>;
def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>;
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
@ -282,6 +284,7 @@ def fmudflapth : Flag<"-fmudflapth">, Group<f_Group>;
def fmudflap : Flag<"-fmudflap">, Group<f_Group>;
def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>;
def fnext_runtime : Flag<"-fnext-runtime">, Group<f_Group>;
def fno_access_control : Flag<"-fno-access-control">, Group<f_Group>;
def fno_asynchronous_unwind_tables : Flag<"-fno-asynchronous-unwind-tables">, Group<f_Group>;
def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, Group<f_Group>;
def fno_blocks : Flag<"-fno-blocks">, Group<f_Group>;
@ -300,6 +303,7 @@ def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>;
def fno_inline_functions : Flag<"-fno-inline-functions">, Group<clang_ignored_f_Group>;
def fno_inline : Flag<"-fno-inline">, Group<clang_ignored_f_Group>;
def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_ignored_f_Group>;
def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Group>;
def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group<f_Group>;
def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group<f_Group>;
@ -312,6 +316,7 @@ def fno_show_source_location : Flag<"-fno-show-source-location">, Group<f_Group>
def fno_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>;
def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<clang_ignored_f_Group>;
def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group<f_Group>;
def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>;
def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group<f_Group>;
def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>;
def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
@ -360,6 +365,7 @@ def funit_at_a_time : Flag<"-funit-at-a-time">, Group<f_Group>;
def funsigned_bitfields : Flag<"-funsigned-bitfields">, Group<f_Group>;
def funsigned_char : Flag<"-funsigned-char">, Group<f_Group>;
def funwind_tables : Flag<"-funwind-tables">, Group<f_Group>;
def fuse_cxa_atexit : Flag<"-fuse-cxa-atexit">, Group<f_Group>;
def fverbose_asm : Flag<"-fverbose-asm">, Group<f_Group>;
def fvisibility_EQ : Joined<"-fvisibility=">, Group<f_Group>;
def fwritable_strings : Flag<"-fwritable-strings">, Group<f_Group>;
@ -390,7 +396,7 @@ def iwithprefix : JoinedOrSeparate<"-iwithprefix">, Group<clang_i_Group>;
def iwithsysroot : JoinedOrSeparate<"-iwithsysroot">, Group<i_Group>;
def i : Joined<"-i">, Group<i_Group>;
def keep__private__externs : Flag<"-keep_private_externs">;
def l : JoinedOrSeparate<"-l">, Flags<[LinkerInput]>;
def l : JoinedOrSeparate<"-l">, Flags<[LinkerInput, RenderJoined]>;
def m32 : Flag<"-m32">, Group<m_Group>, Flags<[DriverOption]>;
def m3dnowa : Flag<"-m3dnowa">, Group<m_x86_Features_Group>;
def m3dnow : Flag<"-m3dnow">, Group<m_x86_Features_Group>;

View File

@ -14,12 +14,14 @@
#ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
#define LLVM_CLANG_FRONTEND_ASTUNIT_H
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/OwningPtr.h"
#include "clang/Basic/FileManager.h"
#include "clang/Index/ASTLocation.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/System/Path.h"
#include <map>
#include <string>
#include <vector>
#include <cassert>
@ -46,6 +48,11 @@ using namespace idx;
/// \brief Utility class for loading a ASTContext from a PCH file.
///
class ASTUnit {
public:
typedef std::map<FileID, std::vector<PreprocessedEntity *> >
PreprocessedEntitiesByFileMap;
private:
FileManager FileMgr;
SourceManager SourceMgr;
@ -53,7 +60,7 @@ class ASTUnit {
llvm::OwningPtr<TargetInfo> Target;
llvm::OwningPtr<Preprocessor> PP;
llvm::OwningPtr<ASTContext> Ctx;
/// Optional owned invocation, just used to make the invocation used in
/// LoadFromCommandLine available.
llvm::OwningPtr<CompilerInvocation> Invocation;
@ -89,6 +96,15 @@ class ASTUnit {
/// destroyed.
llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles;
/// \brief A mapping from file IDs to the set of preprocessed entities
/// stored in that file.
///
/// FIXME: This is just an optimization hack to avoid searching through
/// many preprocessed entities during cursor traversal in the CIndex library.
/// Ideally, we would just be able to perform a binary search within the
/// list of preprocessed entities.
PreprocessedEntitiesByFileMap PreprocessedEntitiesByFile;
/// \brief Simple hack to allow us to assert that ASTUnit is not being
/// used concurrently, which is not supported.
///
@ -162,6 +178,12 @@ public:
return TopLevelDecls;
}
/// \brief Retrieve the mapping from File IDs to the preprocessed entities
/// within that file.
PreprocessedEntitiesByFileMap &getPreprocessedEntitiesByFile() {
return PreprocessedEntitiesByFile;
}
// Retrieve the diagnostics associated with this AST
typedef const StoredDiagnostic * diag_iterator;
diag_iterator diag_begin() const { return Diagnostics.begin(); }

View File

@ -34,7 +34,6 @@ class ExternalASTSource;
class FileManager;
class FrontendAction;
class Preprocessor;
class Source;
class SourceManager;
class TargetInfo;

View File

@ -17,6 +17,22 @@
namespace clang {
class FixItRewriter;
//===----------------------------------------------------------------------===//
// Custom Consumer Actions
//===----------------------------------------------------------------------===//
class InitOnlyAction : public FrontendAction {
virtual void ExecuteAction();
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile);
public:
// Don't claim to only use the preprocessor, we want to follow the AST path,
// but do nothing.
virtual bool usesPreprocessorOnly() const { return false; }
};
//===----------------------------------------------------------------------===//
// AST Consumer Actions
//===----------------------------------------------------------------------===//

View File

@ -36,6 +36,7 @@ namespace frontend {
GeneratePCH, ///< Generate pre-compiled header.
GeneratePTH, ///< Generate pre-tokenized header.
InheritanceView, ///< View C++ inheritance for a specified class.
InitOnly, ///< Only execute frontend initialization.
ParseNoop, ///< Parse with noop callbacks.
ParsePrintCallbacks, ///< Parse and print each callback.
ParseSyntaxOnly, ///< Parse and perform semantic analysis.
@ -71,9 +72,6 @@ public:
unsigned DebugCodeCompletionPrinter : 1; ///< Use the debug printer for code
/// completion results.
unsigned DisableFree : 1; ///< Disable memory freeing on exit.
unsigned EmptyInputOnly : 1; ///< Force input files to be treated
/// as if they were empty, for timing
/// the frontend startup.
unsigned RelocatablePCH : 1; ///< When generating PCH files,
/// instruct the PCH writer to create
/// relocatable PCH files.
@ -117,7 +115,6 @@ public:
FrontendOptions() {
DebugCodeCompletionPrinter = 1;
DisableFree = 0;
EmptyInputOnly = 0;
ProgramAction = frontend::ParseSyntaxOnly;
ActionName = "";
RelocatablePCH = 0;

View File

@ -215,17 +215,18 @@ namespace clang {
/// generate the precompiled header.
ORIGINAL_FILE_NAME = 19,
/// \brief Record code for the sorted array of source ranges where
/// comments were encountered in the source code.
COMMENT_RANGES = 20,
/// Record #20 intentionally left blank.
/// \brief Record code for the version control branch and revision
/// information of the compiler used to build this PCH file.
VERSION_CONTROL_BRANCH_REVISION = 21,
/// \brief Record code for the array of unused static functions.
UNUSED_STATIC_FUNCS = 22
UNUSED_STATIC_FUNCS = 22,
/// \brief Record code for the table of offsets to macro definition
/// entries in the preprocessing record.
MACRO_DEFINITION_OFFSETS = 23
};
/// \brief Record types used within a source manager block.
@ -245,10 +246,7 @@ namespace clang {
SM_SLOC_INSTANTIATION_ENTRY = 4,
/// \brief Describes the SourceManager's line table, with
/// information about #line directives.
SM_LINE_TABLE = 5,
/// \brief Describes one header file info [isImport, DirInfo, NumIncludes]
/// ControllingMacro is optional.
SM_HEADER_FILE_INFO = 6
SM_LINE_TABLE = 5
};
/// \brief Record types used within a preprocessor block.
@ -267,7 +265,14 @@ namespace clang {
/// \brief Describes one token.
/// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags]
PP_TOKEN = 3
PP_TOKEN = 3,
/// \brief Describes a macro instantiation within the preprocessing
/// record.
PP_MACRO_INSTANTIATION = 4,
/// \brief Describes a macro definition within the preprocessing record.
PP_MACRO_DEFINITION = 5
};
/// \defgroup PCHAST Precompiled header AST constants

View File

@ -21,6 +21,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/TemplateBase.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
@ -53,6 +54,7 @@ class Decl;
class DeclContext;
class GotoStmt;
class LabelStmt;
class MacroDefinition;
class NamedDecl;
class Preprocessor;
class Sema;
@ -106,7 +108,7 @@ public:
}
/// \brief Receives a HeaderFileInfo entry.
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {}
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {}
/// \brief Receives __COUNTER__ value.
virtual void ReadCounter(unsigned Value) {}
@ -130,8 +132,11 @@ public:
FileID PCHBufferID,
llvm::StringRef OriginalFileName,
std::string &SuggestedPredefines);
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI);
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID);
virtual void ReadCounter(unsigned Value);
private:
void Error(const char *Msg);
};
/// \brief Reads a precompiled head containing the contents of a
@ -148,13 +153,14 @@ public:
/// actually required will be de-serialized.
class PCHReader
: public ExternalPreprocessorSource,
public ExternalPreprocessingRecordSource,
public ExternalSemaSource,
public IdentifierInfoLookup,
public ExternalIdentifierLookup,
public ExternalSLocEntrySource {
public:
enum PCHReadResult { Success, Failure, IgnorePCH };
friend class PCHValidator;
private:
/// \ brief The receiver of some callbacks invoked by PCHReader.
llvm::OwningPtr<PCHReaderListener> Listener;
@ -293,12 +299,17 @@ private:
/// been loaded.
llvm::SmallVector<Selector, 16> SelectorsLoaded;
/// \brief A sorted array of source ranges containing comments.
SourceRange *Comments;
/// \brief The number of source ranges in the Comments array.
unsigned NumComments;
/// \brief Offsets of all of the macro definitions in the preprocessing
/// record in the PCH file.
const uint32_t *MacroDefinitionOffsets;
/// \brief The macro definitions we have already loaded.
llvm::SmallVector<MacroDefinition *, 16> MacroDefinitionsLoaded;
/// \brief The number of preallocated preprocessing entities in the
/// preprocessing record.
unsigned NumPreallocatedPreprocessingEntities;
/// \brief The set of external definitions stored in the the PCH
/// file.
llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
@ -472,7 +483,7 @@ private:
///
/// This routine should only be used for fatal errors that have to
/// do with non-routine failures (e.g., corrupted PCH file).
bool Error(const char *Msg);
void Error(const char *Msg);
PCHReader(const PCHReader&); // do not implement
PCHReader &operator=(const PCHReader &); // do not implement
@ -524,9 +535,7 @@ public:
}
/// \brief Set the Preprocessor to use.
void setPreprocessor(Preprocessor &pp) {
PP = &pp;
}
void setPreprocessor(Preprocessor &pp);
/// \brief Sets and initializes the given Context.
void InitializeContext(ASTContext &Context);
@ -547,14 +556,9 @@ public:
/// which contains a (typically-empty) subset of the predefines
/// build prior to including the precompiled header.
const std::string &getSuggestedPredefines() { return SuggestedPredefines; }
/// \brief Reads the source ranges that correspond to comments from
/// an external AST source.
///
/// \param Comments the contents of this vector will be
/// replaced with the sorted set of source ranges corresponding to
/// comments in the source code.
virtual void ReadComments(std::vector<SourceRange> &Comments);
/// \brief Read preprocessed entities into the
virtual void ReadPreprocessedEntities();
/// \brief Reads a TemplateArgumentLocInfo appropriate for the
/// given TemplateArgument kind.
@ -724,6 +728,9 @@ public:
/// \brief Read the set of macros defined by this external macro source.
virtual void ReadDefinedMacros();
/// \brief Retrieve the macro definition with the given ID.
MacroDefinition *getMacroDefinition(pch::IdentID ID);
/// \brief Retrieve the AST context that this PCH reader
/// supplements.
ASTContext *getContext() { return Context; }
@ -790,6 +797,10 @@ private:
uint64_t Offset;
};
inline void PCHValidator::Error(const char *Msg) {
Reader.Error(Msg);
}
} // end namespace clang
#endif

View File

@ -33,6 +33,7 @@ namespace clang {
class ASTContext;
class LabelStmt;
class MacroDefinition;
class MemorizeStatCalls;
class Preprocessor;
class Sema;
@ -160,6 +161,14 @@ private:
/// defined.
llvm::DenseMap<const IdentifierInfo *, uint64_t> MacroOffsets;
/// \brief Mapping from macro definitions (as they occur in the preprocessing
/// record) to the index into the macro definitions table.
llvm::DenseMap<const MacroDefinition *, pch::IdentID> MacroDefinitions;
/// \brief Mapping from the macro definition indices in \c MacroDefinitions
/// to the corresponding offsets within the preprocessor block.
std::vector<uint32_t> MacroDefinitionOffsets;
/// \brief Declarations encountered that might be external
/// definitions.
///
@ -206,7 +215,6 @@ private:
const Preprocessor &PP,
const char* isysroot);
void WritePreprocessor(const Preprocessor &PP);
void WriteComments(ASTContext &Context);
void WriteType(QualType T);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
@ -234,6 +242,9 @@ public:
///
/// \param isysroot if non-NULL, write a relocatable PCH file whose headers
/// are relative to the given system root.
///
/// \param PPRec Record of the preprocessing actions that occurred while
/// preprocessing this file, e.g., macro instantiations
void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const char* isysroot);
@ -269,6 +280,10 @@ public:
return MacroOffsets[II];
}
/// \brief Retrieve the ID number corresponding to the given macro
/// definition.
pch::IdentID getMacroDefinitionID(MacroDefinition *MD);
/// \brief Emit a reference to a type.
void AddTypeRef(QualType T, RecordData &Record);

View File

@ -36,6 +36,10 @@ public:
unsigned UsePredefines : 1; /// Initialize the preprocessor with the compiler
/// and target specific predefines.
unsigned DetailedRecord : 1; /// Whether we should maintain a detailed
/// record of all macro definitions and
/// instantiations.
/// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude;
@ -77,7 +81,7 @@ public:
}
public:
PreprocessorOptions() : UsePredefines(true) {}
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false) {}
void addMacroDef(llvm::StringRef Name) {
Macros.push_back(std::make_pair(Name, false));

View File

@ -59,7 +59,7 @@ void InitializePreprocessor(Preprocessor &PP,
/// ProcessWarningOptions - Initialize the diagnostic client and process the
/// warning options specified on the command line.
bool ProcessWarningOptions(Diagnostic &Diags, const DiagnosticOptions &Opts);
void ProcessWarningOptions(Diagnostic &Diags, const DiagnosticOptions &Opts);
/// DoPrintPreprocessedInput - Implement -E mode.
void DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream* OS,

View File

@ -16,7 +16,6 @@
namespace clang {
class Diagnostic;
class SourceMgr;
class TextDiagnosticBuffer;
/// VerifyDiagnosticsClient - Create a diagnostic client which will use markers

View File

@ -214,9 +214,10 @@ public:
void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
typedef std::vector<HeaderFileInfo>::iterator header_file_iterator;
header_file_iterator header_file_begin() { return FileInfo.begin(); }
header_file_iterator header_file_end() { return FileInfo.end(); }
typedef std::vector<HeaderFileInfo>::const_iterator header_file_iterator;
header_file_iterator header_file_begin() const { return FileInfo.begin(); }
header_file_iterator header_file_end() const { return FileInfo.end(); }
unsigned header_file_size() const { return FileInfo.size(); }
// Used by PCHReader.
void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID);

View File

@ -0,0 +1,274 @@
//===--- PreprocessingRecord.h - Record of Preprocessing --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the PreprocessingRecord class, which maintains a record
// of what occurred during preprocessing.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
#define LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
#include "clang/Lex/PPCallbacks.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Allocator.h"
#include <vector>
namespace clang {
class IdentifierInfo;
class PreprocessingRecord;
}
/// \brief Allocates memory within a Clang preprocessing record.
void* operator new(size_t bytes, clang::PreprocessingRecord& PR,
unsigned alignment = 8) throw();
/// \brief Frees memory allocated in a Clang preprocessing record.
void operator delete(void* ptr, clang::PreprocessingRecord& PR,
unsigned) throw();
namespace clang {
class MacroDefinition;
/// \brief Base class that describes a preprocessed entity, which may be a
/// preprocessor directive or macro instantiation.
class PreprocessedEntity {
public:
/// \brief The kind of preprocessed entity an object describes.
enum EntityKind {
/// \brief A macro instantiation.
MacroInstantiationKind,
/// \brief A preprocessing directive whose kind is not specified.
///
/// This kind will be used for any preprocessing directive that does not
/// have a more specific kind within the \c DirectiveKind enumeration.
PreprocessingDirectiveKind,
/// \brief A macro definition.
MacroDefinitionKind,
FirstPreprocessingDirective = PreprocessingDirectiveKind,
LastPreprocessingDirective = MacroDefinitionKind
};
private:
/// \brief The kind of preprocessed entity that this object describes.
EntityKind Kind;
/// \brief The source range that covers this preprocessed entity.
SourceRange Range;
protected:
PreprocessedEntity(EntityKind Kind, SourceRange Range)
: Kind(Kind), Range(Range) { }
public:
/// \brief Retrieve the kind of preprocessed entity stored in this object.
EntityKind getKind() const { return Kind; }
/// \brief Retrieve the source range that covers this entire preprocessed
/// entity.
SourceRange getSourceRange() const { return Range; }
// Implement isa/cast/dyncast/etc.
static bool classof(const PreprocessedEntity *) { return true; }
// Only allow allocation of preprocessed entities using the allocator
// in PreprocessingRecord or by doing a placement new.
void* operator new(size_t bytes, PreprocessingRecord& PR,
unsigned alignment = 8) throw() {
return ::operator new(bytes, PR, alignment);
}
void* operator new(size_t bytes, void* mem) throw() {
return mem;
}
void operator delete(void* ptr, PreprocessingRecord& PR,
unsigned alignment) throw() {
return ::operator delete(ptr, PR, alignment);
}
void operator delete(void*, std::size_t) throw() { }
void operator delete(void*, void*) throw() { }
private:
// Make vanilla 'new' and 'delete' illegal for preprocessed entities.
void* operator new(size_t bytes) throw();
void operator delete(void* data) throw();
};
/// \brief Records the location of a macro instantiation.
class MacroInstantiation : public PreprocessedEntity {
/// \brief The name of the macro being instantiation.
IdentifierInfo *Name;
/// \brief The definition of this macro.
MacroDefinition *Definition;
public:
MacroInstantiation(IdentifierInfo *Name, SourceRange Range,
MacroDefinition *Definition)
: PreprocessedEntity(MacroInstantiationKind, Range), Name(Name),
Definition(Definition) { }
/// \brief The name of the macro being instantiated.
IdentifierInfo *getName() const { return Name; }
/// \brief The definition of the macro being instantiated.
MacroDefinition *getDefinition() const { return Definition; }
// Implement isa/cast/dyncast/etc.
static bool classof(const PreprocessedEntity *PE) {
return PE->getKind() == MacroInstantiationKind;
}
static bool classof(const MacroInstantiation *) { return true; }
};
/// \brief Records the presence of a preprocessor directive.
class PreprocessingDirective : public PreprocessedEntity {
public:
PreprocessingDirective(EntityKind Kind, SourceRange Range)
: PreprocessedEntity(Kind, Range) { }
// Implement isa/cast/dyncast/etc.
static bool classof(const PreprocessedEntity *PD) {
return PD->getKind() >= FirstPreprocessingDirective &&
PD->getKind() <= LastPreprocessingDirective;
}
static bool classof(const PreprocessingDirective *) { return true; }
};
/// \brief Record the location of a macro definition.
class MacroDefinition : public PreprocessingDirective {
/// \brief The name of the macro being defined.
const IdentifierInfo *Name;
/// \brief The location of the macro name in the macro definition.
SourceLocation Location;
public:
explicit MacroDefinition(const IdentifierInfo *Name, SourceLocation Location,
SourceRange Range)
: PreprocessingDirective(MacroDefinitionKind, Range), Name(Name),
Location(Location) { }
/// \brief Retrieve the name of the macro being defined.
const IdentifierInfo *getName() const { return Name; }
/// \brief Retrieve the location of the macro name in the definition.
SourceLocation getLocation() const { return Location; }
// Implement isa/cast/dyncast/etc.
static bool classof(const PreprocessedEntity *PE) {
return PE->getKind() == MacroDefinitionKind;
}
static bool classof(const MacroDefinition *) { return true; }
};
/// \brief An abstract class that should be subclassed by any external source
/// of preprocessing record entries.
class ExternalPreprocessingRecordSource {
public:
virtual ~ExternalPreprocessingRecordSource();
/// \brief Read any preallocated preprocessed entities from the external
/// source.
virtual void ReadPreprocessedEntities() = 0;
};
/// \brief A record of the steps taken while preprocessing a source file,
/// including the various preprocessing directives processed, macros
/// instantiated, etc.
class PreprocessingRecord : public PPCallbacks {
/// \brief Allocator used to store preprocessing objects.
llvm::BumpPtrAllocator BumpAlloc;
/// \brief The set of preprocessed entities in this record, in order they
/// were seen.
std::vector<PreprocessedEntity *> PreprocessedEntities;
/// \brief Mapping from MacroInfo structures to their definitions.
llvm::DenseMap<const MacroInfo *, MacroDefinition *> MacroDefinitions;
/// \brief External source of preprocessed entities.
ExternalPreprocessingRecordSource *ExternalSource;
/// \brief The number of preallocated entities (that are known to the
/// external source).
unsigned NumPreallocatedEntities;
/// \brief Whether we have already loaded all of the preallocated entities.
mutable bool LoadedPreallocatedEntities;
void MaybeLoadPreallocatedEntities() const ;
public:
PreprocessingRecord();
/// \brief Allocate memory in the preprocessing record.
void *Allocate(unsigned Size, unsigned Align = 8) {
return BumpAlloc.Allocate(Size, Align);
}
/// \brief Deallocate memory in the preprocessing record.
void Deallocate(void *Ptr) { }
// Iteration over the preprocessed entities.
typedef std::vector<PreprocessedEntity *>::iterator iterator;
typedef std::vector<PreprocessedEntity *>::const_iterator const_iterator;
iterator begin(bool OnlyLocalEntities = false);
iterator end(bool OnlyLocalEntities = false);
const_iterator begin(bool OnlyLocalEntities = false) const;
const_iterator end(bool OnlyLocalEntities = false) const;
/// \brief Add a new preprocessed entity to this record.
void addPreprocessedEntity(PreprocessedEntity *Entity);
/// \brief Set the external source for preprocessed entities.
void SetExternalSource(ExternalPreprocessingRecordSource &Source,
unsigned NumPreallocatedEntities);
/// \brief Set the preallocated entry at the given index to the given
/// preprocessed entity.
void SetPreallocatedEntity(unsigned Index, PreprocessedEntity *Entity);
/// \brief Register a new macro definition.
void RegisterMacroDefinition(MacroInfo *Macro, MacroDefinition *MD);
/// \brief Retrieve the preprocessed entity at the given index.
PreprocessedEntity *getPreprocessedEntity(unsigned Index) {
assert(Index < PreprocessedEntities.size() &&
"Out-of-bounds preprocessed entity");
return PreprocessedEntities[Index];
}
/// \brief Retrieve the macro definition that corresponds to the given
/// \c MacroInfo.
MacroDefinition *findMacroDefinition(const MacroInfo *MI);
virtual void MacroExpands(const Token &Id, const MacroInfo* MI);
virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
virtual void MacroUndefined(const IdentifierInfo *II, const MacroInfo *MI);
};
} // end namespace clang
inline void* operator new(size_t bytes, clang::PreprocessingRecord& PR,
unsigned alignment) throw() {
return PR.Allocate(bytes, alignment);
}
inline void operator delete(void* ptr, clang::PreprocessingRecord& PR,
unsigned) throw() {
PR.Deallocate(ptr);
}
#endif // LLVM_CLANG_LEX_PREPROCESSINGRECORD_H

View File

@ -43,7 +43,8 @@ class ScratchBuffer;
class TargetInfo;
class PPCallbacks;
class DirectoryLookup;
class PreprocessingRecord;
/// Preprocessor - This object engages in a tight little dance with the lexer to
/// efficiently preprocess tokens. Lexers know only about tokens within a
/// single source file, and don't know anything about preprocessor-level issues
@ -209,6 +210,13 @@ class Preprocessor {
unsigned NumCachedTokenLexers;
TokenLexer *TokenLexerCache[TokenLexerCacheSize];
/// \brief A record of the macro definitions and instantiations that
/// occurred during preprocessing.
///
/// This is an optional side structure that can be enabled with
/// \c createPreprocessingRecord() prior to preprocessing.
PreprocessingRecord *Record;
private: // Cached tokens state.
typedef llvm::SmallVector<Token, 1> CachedTokensTy;
@ -348,9 +356,17 @@ public:
/// It is an error to remove a handler that has not been registered.
void RemoveCommentHandler(CommentHandler *Handler);
/// \brief Retrieve the preprocessing record, or NULL if there is no
/// preprocessing record.
PreprocessingRecord *getPreprocessingRecord() const { return Record; }
/// \brief Create a new preprocessing record, which will keep track of
/// all macro expansions, macro definitions, etc.
void createPreprocessingRecord();
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
void EnterMainSourceFile();
bool EnterMainSourceFile();
/// EnterSourceFile - Add a source file to the top of the include stack and
/// start lexing tokens from it instead of the current buffer. Return true
@ -595,7 +611,7 @@ public:
// Otherwise, fall back on getCharacterData, which is slower, but always
// works.
return *SourceMgr.getCharacterData(Tok.getLocation());
return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid);
}
/// CreateString - Plop the specified string into a scratch buffer and set the

View File

@ -153,10 +153,6 @@ public:
/// an empty string if not. This is used for pretty crash reporting.
virtual std::string getDeclName(DeclPtrTy D) { return ""; }
/// \brief Invoked for each comment in the source code, providing the source
/// range that contains the comment.
virtual void ActOnComment(SourceRange Comment) { }
//===--------------------------------------------------------------------===//
// Declaration Tracking Callbacks.
//===--------------------------------------------------------------------===//
@ -727,9 +723,17 @@ public:
/// ActOnTagFinishDefinition - Invoked once we have finished parsing
/// the definition of a tag (enumeration, class, struct, or union).
///
/// The scope is the scope of the tag definition.
virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
SourceLocation RBraceLoc) { }
/// ActOnTagDefinitionError - Invoked if there's an unrecoverable
/// error parsing the definition of a tag.
///
/// The scope is the scope of the tag definition.
virtual void ActOnTagDefinitionError(Scope *S, DeclPtrTy TagDecl) { }
virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl,
DeclPtrTy LastEnumConstant,
SourceLocation IdLoc, IdentifierInfo *Id,

View File

@ -90,7 +90,6 @@ class Parser {
llvm::OwningPtr<PragmaHandler> PackHandler;
llvm::OwningPtr<PragmaHandler> UnusedHandler;
llvm::OwningPtr<PragmaHandler> WeakHandler;
llvm::OwningPtr<clang::CommentHandler> CommentHandler;
/// Whether the '>' token acts as an operator or not. This will be
/// true except when we are parsing an expression within a C++

View File

@ -43,8 +43,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0),
ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
SourceMgr(SM), LangOpts(LOpts),
LoadedExternalComments(false), FreeMemory(FreeMem), Target(t),
SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t),
Idents(idents), Selectors(sels),
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
ObjCIdRedefinitionType = QualType();
@ -413,201 +412,6 @@ namespace {
};
}
/// \brief Determine whether the given comment is a Doxygen-style comment.
///
/// \param Start the start of the comment text.
///
/// \param End the end of the comment text.
///
/// \param Member whether we want to check whether this is a member comment
/// (which requires a < after the Doxygen-comment delimiter). Otherwise,
/// we only return true when we find a non-member comment.
static bool
isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
bool Member = false) {
bool Invalid = false;
const char *BufferStart
= SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin()),
&Invalid).data();
if (Invalid)
return false;
const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin());
const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd());
if (End - Start < 4)
return false;
assert(Start[0] == '/' && "Not a comment?");
if (Start[1] == '*' && !(Start[2] == '!' || Start[2] == '*'))
return false;
if (Start[1] == '/' && !(Start[2] == '!' || Start[2] == '/'))
return false;
return (Start[3] == '<') == Member;
}
/// \brief Retrieve the comment associated with the given declaration, if
/// it has one.
const char *ASTContext::getCommentForDecl(const Decl *D) {
if (!D)
return 0;
// Check whether we have cached a comment string for this declaration
// already.
llvm::DenseMap<const Decl *, std::string>::iterator Pos
= DeclComments.find(D);
if (Pos != DeclComments.end())
return Pos->second.c_str();
// If we have an external AST source and have not yet loaded comments from
// that source, do so now.
if (ExternalSource && !LoadedExternalComments) {
std::vector<SourceRange> LoadedComments;
ExternalSource->ReadComments(LoadedComments);
if (!LoadedComments.empty())
Comments.insert(Comments.begin(), LoadedComments.begin(),
LoadedComments.end());
LoadedExternalComments = true;
}
// If there are no comments anywhere, we won't find anything.
if (Comments.empty())
return 0;
// If the declaration doesn't map directly to a location in a file, we
// can't find the comment.
SourceLocation DeclStartLoc = D->getLocStart();
if (DeclStartLoc.isInvalid() || !DeclStartLoc.isFileID())
return 0;
// Find the comment that occurs just before this declaration.
std::vector<SourceRange>::iterator LastComment
= std::lower_bound(Comments.begin(), Comments.end(),
SourceRange(DeclStartLoc),
BeforeInTranslationUnit(&SourceMgr));
// Decompose the location for the start of the declaration and find the
// beginning of the file buffer.
std::pair<FileID, unsigned> DeclStartDecomp
= SourceMgr.getDecomposedLoc(DeclStartLoc);
bool Invalid = false;
const char *FileBufferStart
= SourceMgr.getBufferData(DeclStartDecomp.first, &Invalid).data();
if (Invalid)
return 0;
// First check whether we have a comment for a member.
if (LastComment != Comments.end() &&
!isa<TagDecl>(D) && !isa<NamespaceDecl>(D) &&
isDoxygenComment(SourceMgr, *LastComment, true)) {
std::pair<FileID, unsigned> LastCommentEndDecomp
= SourceMgr.getDecomposedLoc(LastComment->getEnd());
if (DeclStartDecomp.first == LastCommentEndDecomp.first &&
SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second)
== SourceMgr.getLineNumber(LastCommentEndDecomp.first,
LastCommentEndDecomp.second)) {
// The Doxygen member comment comes after the declaration starts and
// is on the same line and in the same file as the declaration. This
// is the comment we want.
std::string &Result = DeclComments[D];
Result.append(FileBufferStart +
SourceMgr.getFileOffset(LastComment->getBegin()),
FileBufferStart + LastCommentEndDecomp.second + 1);
return Result.c_str();
}
}
if (LastComment == Comments.begin())
return 0;
--LastComment;
// Decompose the end of the comment.
std::pair<FileID, unsigned> LastCommentEndDecomp
= SourceMgr.getDecomposedLoc(LastComment->getEnd());
// If the comment and the declaration aren't in the same file, then they
// aren't related.
if (DeclStartDecomp.first != LastCommentEndDecomp.first)
return 0;
// Check that we actually have a Doxygen comment.
if (!isDoxygenComment(SourceMgr, *LastComment))
return 0;
// Compute the starting line for the declaration and for the end of the
// comment (this is expensive).
unsigned DeclStartLine
= SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second);
unsigned CommentEndLine
= SourceMgr.getLineNumber(LastCommentEndDecomp.first,
LastCommentEndDecomp.second);
// If the comment does not end on the line prior to the declaration, then
// the comment is not associated with the declaration at all.
if (CommentEndLine + 1 != DeclStartLine)
return 0;
// We have a comment, but there may be more comments on the previous lines.
// Keep looking so long as the comments are still Doxygen comments and are
// still adjacent.
unsigned ExpectedLine
= SourceMgr.getSpellingLineNumber(LastComment->getBegin()) - 1;
std::vector<SourceRange>::iterator FirstComment = LastComment;
while (FirstComment != Comments.begin()) {
// Look at the previous comment
--FirstComment;
std::pair<FileID, unsigned> Decomp
= SourceMgr.getDecomposedLoc(FirstComment->getEnd());
// If this previous comment is in a different file, we're done.
if (Decomp.first != DeclStartDecomp.first) {
++FirstComment;
break;
}
// If this comment is not a Doxygen comment, we're done.
if (!isDoxygenComment(SourceMgr, *FirstComment)) {
++FirstComment;
break;
}
// If the line number is not what we expected, we're done.
unsigned Line = SourceMgr.getLineNumber(Decomp.first, Decomp.second);
if (Line != ExpectedLine) {
++FirstComment;
break;
}
// Set the next expected line number.
ExpectedLine
= SourceMgr.getSpellingLineNumber(FirstComment->getBegin()) - 1;
}
// The iterator range [FirstComment, LastComment] contains all of the
// BCPL comments that, together, are associated with this declaration.
// Form a single comment block string for this declaration that concatenates
// all of these comments.
std::string &Result = DeclComments[D];
while (FirstComment != LastComment) {
std::pair<FileID, unsigned> DecompStart
= SourceMgr.getDecomposedLoc(FirstComment->getBegin());
std::pair<FileID, unsigned> DecompEnd
= SourceMgr.getDecomposedLoc(FirstComment->getEnd());
Result.append(FileBufferStart + DecompStart.second,
FileBufferStart + DecompEnd.second + 1);
++FirstComment;
}
// Append the last comment line.
Result.append(FileBufferStart +
SourceMgr.getFileOffset(LastComment->getBegin()),
FileBufferStart + LastCommentEndDecomp.second + 1);
return Result.c_str();
}
//===----------------------------------------------------------------------===//
// Type Sizing and Analysis
//===----------------------------------------------------------------------===//
@ -4315,6 +4119,41 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
return false;
}
/// canAssignObjCInterfacesInBlockPointer - This routine is specifically written
/// for providing type-safty for objective-c pointers used to pass/return
/// arguments in block literals. When passed as arguments, passing 'A*' where
/// 'id' is expected is not OK. Passing 'Sub *" where 'Super *" is expected is
/// not OK. For the return type, the opposite is not OK.
bool ASTContext::canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT) {
if (RHSOPT->isObjCBuiltinType())
return true;
if (LHSOPT->isObjCBuiltinType()) {
return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
}
if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
QualType(RHSOPT,0),
false);
const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
if (LHS && RHS) { // We have 2 user-defined types.
if (LHS != RHS) {
if (LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
return false;
if (RHS->getDecl()->isSuperClassOf(LHS->getDecl()))
return true;
}
else
return true;
}
return false;
}
/// getIntersectionOfProtocols - This routine finds the intersection of set
/// of protocols inherited from two distinct objective-c pointer objects.
/// It is used to build composite qualifier list of the composite type of
@ -4451,7 +4290,12 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
return !mergeTypes(LHS, RHS).isNull();
}
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
bool ASTContext::typesAreBlockPointerCompatible(QualType LHS, QualType RHS) {
return !mergeTypes(LHS, RHS, true).isNull();
}
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
bool OfBlockPointer) {
const FunctionType *lbase = lhs->getAs<FunctionType>();
const FunctionType *rbase = rhs->getAs<FunctionType>();
const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase);
@ -4460,7 +4304,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
bool allRTypes = true;
// Check return type
QualType retType = mergeTypes(lbase->getResultType(), rbase->getResultType());
QualType retType;
if (OfBlockPointer)
retType = mergeTypes(rbase->getResultType(), lbase->getResultType(), true);
else
retType = mergeTypes(lbase->getResultType(), rbase->getResultType());
if (retType.isNull()) return QualType();
if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType()))
allLTypes = false;
@ -4500,7 +4348,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
for (unsigned i = 0; i < lproto_nargs; i++) {
QualType largtype = lproto->getArgType(i).getUnqualifiedType();
QualType rargtype = rproto->getArgType(i).getUnqualifiedType();
QualType argtype = mergeTypes(largtype, rargtype);
QualType argtype = mergeTypes(largtype, rargtype, OfBlockPointer);
if (argtype.isNull()) return QualType();
types.push_back(argtype);
if (getCanonicalType(argtype) != getCanonicalType(largtype))
@ -4554,7 +4402,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
return getFunctionNoProtoType(retType, NoReturn, lcc);
}
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
bool OfBlockPointer) {
// C++ [expr]: If an expression initially has the type "reference to T", the
// type is adjusted to "T" prior to any further analysis, the expression
// designates the object or function denoted by the reference, and the
@ -4681,7 +4530,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
// Merge two block pointer types, while trying to preserve typedef info
QualType LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType();
QualType RHSPointee = RHS->getAs<BlockPointerType>()->getPointeeType();
QualType ResultType = mergeTypes(LHSPointee, RHSPointee);
QualType ResultType = mergeTypes(LHSPointee, RHSPointee, OfBlockPointer);
if (ResultType.isNull()) return QualType();
if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType))
return LHS;
@ -4732,7 +4581,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
ArrayType::ArraySizeModifier(), 0);
}
case Type::FunctionNoProto:
return mergeFunctionTypes(LHS, RHS);
return mergeFunctionTypes(LHS, RHS, OfBlockPointer);
case Type::Record:
case Type::Enum:
return QualType();
@ -4761,12 +4610,19 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return QualType();
}
case Type::ObjCObjectPointer: {
if (OfBlockPointer) {
if (canAssignObjCInterfacesInBlockPointer(
LHS->getAs<ObjCObjectPointerType>(),
RHS->getAs<ObjCObjectPointerType>()))
return LHS;
return QualType();
}
if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(),
RHS->getAs<ObjCObjectPointerType>()))
return LHS;
return QualType();
}
}
}
return QualType();

View File

@ -430,7 +430,10 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
for (; I!=End; ++I)
QualName += *I + "::";
QualName += getNameAsString();
if (getDeclName())
QualName += getNameAsString();
else
QualName += "<anonymous>";
return QualName;
}

View File

@ -743,7 +743,10 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
}
ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const {
return getClassInterface()->FindCategoryDeclaration(getIdentifier());
// The class interface might be NULL if we are working with invalid code.
if (const ObjCInterfaceDecl *ID = getClassInterface())
return ID->FindCategoryDeclaration(getIdentifier());
return 0;
}

View File

@ -227,7 +227,12 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
llvm::raw_svector_ostream Out(Name);
Out << (MD->isInstanceMethod() ? '-' : '+');
Out << '[';
Out << MD->getClassInterface()->getNameAsString();
// For incorrect code, there might not be an ObjCInterfaceDecl. Do
// a null check to avoid a crash.
if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
Out << ID->getNameAsString();
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) {
Out << '(';
@ -1104,11 +1109,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (m->isArrow())
return LV_Valid;
Expr *BaseExp = m->getBase();
if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass)
if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass ||
BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass)
return LV_SubObjCPropertySetting;
return
(BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass) ?
LV_SubObjCPropertyGetterSetting : BaseExp->isLvalue(Ctx);
BaseExp->isLvalue(Ctx);
}
case UnaryOperatorClass:
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
@ -1324,8 +1329,6 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
return MLV_InvalidExpression;
case LV_MemberFunction: return MLV_MemberFunction;
case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
case LV_SubObjCPropertyGetterSetting:
return MLV_SubObjCPropertyGetterSetting;
case LV_ClassTemporary:
return MLV_ClassTemporary;
}

View File

@ -406,27 +406,34 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (!EvaluatePointer(PExp, ResultLValue, Info))
return APValue();
llvm::APSInt AdditionalOffset(32);
llvm::APSInt AdditionalOffset;
if (!EvaluateInteger(IExp, AdditionalOffset, Info))
return APValue();
QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType();
CharUnits SizeOfPointee;
// Compute the new offset in the appropriate width.
QualType PointeeType =
PExp->getType()->getAs<PointerType>()->getPointeeType();
llvm::APSInt SizeOfPointee(AdditionalOffset);
// Explicitly handle GNU void* and function pointer arithmetic extensions.
if (PointeeType->isVoidType() || PointeeType->isFunctionType())
SizeOfPointee = CharUnits::One();
SizeOfPointee = 1;
else
SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType);
CharUnits Offset = ResultLValue.getLValueOffset();
SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType).getQuantity();
llvm::APSInt Offset(AdditionalOffset);
Offset = ResultLValue.getLValueOffset().getQuantity();
if (E->getOpcode() == BinaryOperator::Add)
Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee;
Offset += AdditionalOffset * SizeOfPointee;
else
Offset -= AdditionalOffset.getLimitedValue() * SizeOfPointee;
Offset -= AdditionalOffset * SizeOfPointee;
return APValue(ResultLValue.getLValueBase(), Offset);
// Sign extend prior to converting back to a char unit.
if (Offset.getBitWidth() < 64)
Offset.extend(64);
return APValue(ResultLValue.getLValueBase(),
CharUnits::fromQuantity(Offset.getLimitedValue()));
}
APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {

View File

@ -18,6 +18,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@ -412,10 +413,12 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
return;
std::string Buffer;
bool HasKindDecoration = false;
// We don't print tags unless this is an elaborated type.
// In C, we just assume every RecordType is an elaborated type.
if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) {
HasKindDecoration = true;
Buffer += D->getKindName();
Buffer += ' ';
}
@ -425,15 +428,31 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
// this will always be empty.
AppendScope(D->getDeclContext(), Buffer);
const char *ID;
if (const IdentifierInfo *II = D->getIdentifier())
ID = II->getNameStart();
Buffer += II->getNameStart();
else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) {
assert(Typedef->getIdentifier() && "Typedef without identifier?");
ID = Typedef->getIdentifier()->getNameStart();
} else
ID = "<anonymous>";
Buffer += ID;
Buffer += Typedef->getIdentifier()->getNameStart();
} else {
// Make an unambiguous representation for anonymous types, e.g.
// <anonymous enum at /usr/include/string.h:120:9>
llvm::raw_string_ostream OS(Buffer);
OS << "<anonymous";
// Suppress the redundant tag keyword if we just printed one.
// We don't have to worry about ElaboratedTypes here because you can't
// refer to an anonymous type with one.
if (!HasKindDecoration)
OS << " " << D->getKindName();
PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc(
D->getLocation());
OS << " at " << PLoc.getFilename()
<< ':' << PLoc.getLine()
<< ':' << PLoc.getColumn()
<< '>';
OS.flush();
}
// If this is a class template specialization, print the template
// arguments.

View File

@ -80,24 +80,24 @@ FullSourceLoc FullSourceLoc::getSpellingLoc() const {
return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr);
}
unsigned FullSourceLoc::getInstantiationLineNumber() const {
unsigned FullSourceLoc::getInstantiationLineNumber(bool *Invalid) const {
assert(isValid());
return SrcMgr->getInstantiationLineNumber(*this);
return SrcMgr->getInstantiationLineNumber(*this, Invalid);
}
unsigned FullSourceLoc::getInstantiationColumnNumber() const {
unsigned FullSourceLoc::getInstantiationColumnNumber(bool *Invalid) const {
assert(isValid());
return SrcMgr->getInstantiationColumnNumber(*this);
return SrcMgr->getInstantiationColumnNumber(*this, Invalid);
}
unsigned FullSourceLoc::getSpellingLineNumber() const {
unsigned FullSourceLoc::getSpellingLineNumber(bool *Invalid) const {
assert(isValid());
return SrcMgr->getSpellingLineNumber(*this);
return SrcMgr->getSpellingLineNumber(*this, Invalid);
}
unsigned FullSourceLoc::getSpellingColumnNumber() const {
unsigned FullSourceLoc::getSpellingColumnNumber(bool *Invalid) const {
assert(isValid());
return SrcMgr->getSpellingColumnNumber(*this);
return SrcMgr->getSpellingColumnNumber(*this, Invalid);
}
bool FullSourceLoc::isInSystemHeader() const {
@ -105,18 +105,18 @@ bool FullSourceLoc::isInSystemHeader() const {
return SrcMgr->isInSystemHeader(*this);
}
const char *FullSourceLoc::getCharacterData() const {
const char *FullSourceLoc::getCharacterData(bool *Invalid) const {
assert(isValid());
return SrcMgr->getCharacterData(*this);
return SrcMgr->getCharacterData(*this, Invalid);
}
const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const {
const llvm::MemoryBuffer* FullSourceLoc::getBuffer(bool *Invalid) const {
assert(isValid());
return SrcMgr->getBuffer(SrcMgr->getFileID(*this));
return SrcMgr->getBuffer(SrcMgr->getFileID(*this), Invalid);
}
llvm::StringRef FullSourceLoc::getBufferData() const {
return getBuffer()->getBuffer();
llvm::StringRef FullSourceLoc::getBufferData(bool *Invalid) const {
return getBuffer(Invalid)->getBuffer();
}
std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const {

View File

@ -32,14 +32,14 @@ using llvm::MemoryBuffer;
//===----------------------------------------------------------------------===//
ContentCache::~ContentCache() {
delete Buffer;
delete Buffer.getPointer();
}
/// getSizeBytesMapped - Returns the number of bytes actually mapped for
/// this ContentCache. This can be 0 if the MemBuffer was not actually
/// instantiated.
unsigned ContentCache::getSizeBytesMapped() const {
return Buffer ? Buffer->getBufferSize() : 0;
return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0;
}
/// getSize - Returns the size of the content encapsulated by this ContentCache.
@ -47,15 +47,16 @@ unsigned ContentCache::getSizeBytesMapped() const {
/// scratch buffer. If the ContentCache encapsulates a source file, that
/// file is not lazily brought in from disk to satisfy this query.
unsigned ContentCache::getSize() const {
return Buffer ? (unsigned) Buffer->getBufferSize()
: (unsigned) Entry->getSize();
return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize()
: (unsigned) Entry->getSize();
}
void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
assert(B != Buffer);
assert(B != Buffer.getPointer());
delete Buffer;
Buffer = B;
delete Buffer.getPointer();
Buffer.setPointer(B);
Buffer.setInt(false);
}
const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
@ -64,12 +65,13 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
*Invalid = false;
// Lazily create the Buffer for ContentCaches that wrap files.
if (!Buffer && Entry) {
if (!Buffer.getPointer() && Entry) {
std::string ErrorStr;
struct stat FileInfo;
Buffer = MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
Entry->getSize(), &FileInfo);
Buffer.setPointer(MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
Entry->getSize(), &FileInfo));
Buffer.setInt(false);
// If we were unable to open the file, then we are in an inconsistent
// situation where the content cache referenced a file which no longer
// exists. Most likely, we were using a stat cache with an invalid entry but
@ -80,34 +82,31 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
// currently handle returning a null entry here. Ideally we should detect
// that we are in an inconsistent situation and error out as quickly as
// possible.
if (!Buffer) {
if (!Buffer.getPointer()) {
const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
Buffer = MemoryBuffer::getNewMemBuffer(Entry->getSize(), "<invalid>");
char *Ptr = const_cast<char*>(Buffer->getBufferStart());
Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(),
"<invalid>"));
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
Diag.Report(diag::err_cannot_open_file)
<< Entry->getName() << ErrorStr;
if (Invalid)
*Invalid = true;
} else {
// Check that the file's size and modification time is the same as
// in the file entry (which may have come from a stat cache).
if (FileInfo.st_size != Entry->getSize()) {
Diag.Report(diag::err_file_size_changed)
<< Entry->getName() << (unsigned)Entry->getSize()
<< (unsigned)FileInfo.st_size;
if (Invalid)
*Invalid = true;
} else if (FileInfo.st_mtime != Entry->getModificationTime()) {
Diag.Report(diag::err_file_modified) << Entry->getName();
if (Invalid)
*Invalid = true;
}
Buffer.setInt(true);
} else if (FileInfo.st_size != Entry->getSize() ||
FileInfo.st_mtime != Entry->getModificationTime() ||
FileInfo.st_ino != Entry->getInode()) {
// Check that the file's size, modification time, and inode are
// the same as in the file entry (which may have come from a
// stat cache).
Diag.Report(diag::err_file_modified) << Entry->getName();
Buffer.setInt(true);
}
}
return Buffer;
if (Invalid)
*Invalid = Buffer.getInt();
return Buffer.getPointer();
}
unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) {
@ -412,7 +411,7 @@ FileID SourceManager::createFileID(const ContentCache *File,
= SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter));
SLocEntryLoaded[PreallocatedID] = true;
FileID FID = FileID::get(PreallocatedID);
return LastFileIDLookup = FID;
return FID;
}
SLocEntryTable.push_back(SLocEntry::get(NextOffset,
@ -475,15 +474,14 @@ bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
}
llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
bool MyInvalid = false;
const llvm::MemoryBuffer *Buf = getBuffer(FID, &MyInvalid);
if (Invalid)
*Invalid = false;
const llvm::MemoryBuffer *Buf = getBuffer(FID);
if (!Buf) {
if (*Invalid)
*Invalid = true;
*Invalid = MyInvalid;
if (MyInvalid)
return "";
}
return Buf->getBuffer();
}

View File

@ -72,7 +72,9 @@ public:
/// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values.
/// It updatees the GRState object in place with the values removed.
Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
Store RemoveDeadBindings(Store store, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
void iterBindings(Store store, BindingsHandler& f);
@ -250,6 +252,7 @@ Store BasicStoreManager::Remove(Store store, Loc loc) {
}
Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{

View File

@ -36,6 +36,23 @@ BugReporterContext::~BugReporterContext() {
if ((*I)->isOwnedByReporterContext()) delete *I;
}
void BugReporterContext::addVisitor(BugReporterVisitor* visitor) {
if (!visitor)
return;
llvm::FoldingSetNodeID ID;
visitor->Profile(ID);
void *InsertPos;
if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
delete visitor;
return;
}
CallbacksSet.InsertNode(visitor, InsertPos);
Callbacks = F.Add(visitor, Callbacks);
}
//===----------------------------------------------------------------------===//
// Helper routines for walking the ExplodedGraph and fetching statements.
//===----------------------------------------------------------------------===//
@ -1613,7 +1630,9 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
else
return;
// Register node visitors.
R->registerInitialVisitors(PDB, N);
bugreporter::registerNilReceiverVisitor(PDB);
switch (PDB.getGenerationScheme()) {
case PathDiagnosticClient::Extensive:

View File

@ -92,6 +92,13 @@ public:
FindLastStoreBRVisitor(SVal v, const MemRegion *r)
: R(r), V(v), satisfied(false), StoreSite(0) {}
virtual void Profile(llvm::FoldingSetNodeID &ID) const {
static int tag = 0;
ID.AddPointer(&tag);
ID.AddPointer(R);
ID.Add(V);
}
PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext& BRC) {
@ -129,8 +136,8 @@ public:
return NULL;
satisfied = true;
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
llvm::SmallString<256> sbuf;
llvm::raw_svector_ostream os(sbuf);
if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
@ -239,6 +246,13 @@ public:
TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
: Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
void Profile(llvm::FoldingSetNodeID &ID) const {
static int tag = 0;
ID.AddPointer(&tag);
ID.AddBoolean(Assumption);
ID.Add(Constraint);
}
PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext& BRC) {
@ -365,3 +379,52 @@ void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC,
BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
}
namespace {
class NilReceiverVisitor : public BugReporterVisitor {
public:
NilReceiverVisitor() {}
void Profile(llvm::FoldingSetNodeID &ID) const {
static int x = 0;
ID.AddPointer(&x);
}
PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext& BRC) {
const PostStmt *P = N->getLocationAs<PostStmt>();
if (!P)
return 0;
const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
if (!ME)
return 0;
const Expr *Receiver = ME->getReceiver();
if (!Receiver)
return 0;
const GRState *state = N->getState();
const SVal &V = state->getSVal(Receiver);
const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
if (!DV)
return 0;
state = state->Assume(*DV, true);
if (state)
return 0;
// The receiver was nil, and hence the method was skipped.
// Register a BugReporterVisitor to issue a message telling us how
// the receiver was null.
bugreporter::registerTrackNullOrUndefValue(BRC, Receiver, N);
// Issue a message saying that the method was skipped.
PathDiagnosticLocation L(Receiver, BRC.getSourceManager());
return new PathDiagnosticEventPiece(L, "No method actually called "
"because the receiver is nil");
}
};
} // end anonymous namespace
void clang::bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) {
BRC.addVisitor(new NilReceiverVisitor());
}

View File

@ -24,7 +24,7 @@ namespace {
class CallAndMessageChecker
: public CheckerVisitor<CallAndMessageChecker> {
BugType *BT_call_null;
BugType *BT_call_undef;
BugType *BT_call_undef;
BugType *BT_call_arg;
BugType *BT_msg_undef;
BugType *BT_msg_arg;
@ -44,12 +44,20 @@ public:
bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
private:
bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
const char *BT_desc, BugType *&BT);
void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
ExplodedNode *N);
void HandleNilReceiver(CheckerContext &C, const GRState *state,
const ObjCMessageExpr *ME);
const ObjCMessageExpr *ME);
void LazyInit_BT(const char *desc, BugType *&BT) {
if (!BT)
BT = new BuiltinBug(desc);
}
};
} // end anonymous namespace
@ -62,19 +70,127 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
ExplodedNode *N = C.GenerateSink();
if (!N)
return;
EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetCalleeExpr(N));
C.EmitReport(R);
}
void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
const Expr *Ex,
const char *BT_desc,
BugType *&BT) {
const SVal &V = C.getState()->getSVal(Ex);
if (V.isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
LazyInit_BT(BT_desc, BT);
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
R->addRange(Ex->getSourceRange());
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
C.EmitReport(R);
}
return true;
}
if (const nonloc::LazyCompoundVal *LV =
dyn_cast<nonloc::LazyCompoundVal>(&V)) {
class FindUninitializedField {
public:
llvm::SmallVector<const FieldDecl *, 10> FieldChain;
private:
ASTContext &C;
StoreManager &StoreMgr;
MemRegionManager &MrMgr;
Store store;
public:
FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
MemRegionManager &mrMgr, Store s)
: C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
bool Find(const TypedRegion *R) {
QualType T = R->getValueType(C);
if (const RecordType *RT = T->getAsStructureType()) {
const RecordDecl *RD = RT->getDecl()->getDefinition();
assert(RD && "Referred record has no definition");
for (RecordDecl::field_iterator I =
RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
FieldChain.push_back(*I);
T = (*I)->getType();
if (T->getAsStructureType()) {
if (Find(FR))
return true;
}
else {
const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
if (V.isUndef())
return true;
}
FieldChain.pop_back();
}
}
return false;
}
};
const LazyCompoundValData *D = LV->getCVData();
FindUninitializedField F(C.getASTContext(),
C.getState()->getStateManager().getStoreManager(),
C.getValueManager().getRegionManager(),
D->getStore());
if (F.Find(D->getRegion())) {
if (ExplodedNode *N = C.GenerateSink()) {
LazyInit_BT(BT_desc, BT);
llvm::SmallString<512> Str;
llvm::raw_svector_ostream os(Str);
os << "Passed-by-value struct argument contains uninitialized data";
if (F.FieldChain.size() == 1)
os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString()
<< "')";
else {
os << " (e.g., via the field chain: '";
bool first = true;
for (llvm::SmallVectorImpl<const FieldDecl *>::iterator
DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
if (first)
first = false;
else
os << '.';
os << (*DI)->getNameAsString();
}
os << "')";
}
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
R->addRange(Ex->getSourceRange());
// FIXME: enhance track back for uninitialized value for arbitrary
// memregions
C.EmitReport(R);
}
return true;
}
}
return false;
}
void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
const CallExpr *CE){
const Expr *Callee = CE->getCallee()->IgnoreParens();
SVal L = C.getState()->getSVal(Callee);
if (L.isUndef()) {
if (!BT_call_undef)
BT_call_undef =
@ -82,31 +198,20 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
EmitBadCall(BT_call_undef, C, CE);
return;
}
if (isa<loc::ConcreteInt>(L)) {
if (!BT_call_null)
BT_call_null =
new BuiltinBug("Called function pointer is null (null dereference)");
EmitBadCall(BT_call_null, C, CE);
}
for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
if (C.getState()->getSVal(*I).isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_call_arg)
BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
" is undefined");
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
BT_call_arg->getName(), N);
R->addRange((*I)->getSourceRange());
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
C.EmitReport(R);
return;
}
}
}
for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I)
if (PreVisitProcessArg(C, *I,
"Pass-by-value argument in function call is"
" undefined", BT_call_arg))
return;
}
void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
@ -132,23 +237,11 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
// Check for any arguments that are uninitialized/undefined.
for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
E = ME->arg_end(); I != E; ++I) {
if (state->getSVal(*I).isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_msg_arg)
BT_msg_arg =
new BuiltinBug("Pass-by-value argument in message expression"
" is undefined");
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
BT_msg_arg->getName(), N);
R->addRange((*I)->getSourceRange());
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
C.EmitReport(R);
E = ME->arg_end(); I != E; ++I)
if (PreVisitProcessArg(C, *I,
"Pass-by-value argument in message expression "
"is undefined", BT_msg_arg))
return;
}
}
}
}
bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
@ -160,24 +253,24 @@ bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
const ObjCMessageExpr *ME,
ExplodedNode *N) {
if (!BT_msg_ret)
BT_msg_ret =
new BuiltinBug("Receiver in message expression is "
"'nil' and returns a garbage value");
llvm::SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The receiver of message '" << ME->getSelector().getAsString()
<< "' is nil and returns a value of type '"
<< ME->getType().getAsString() << "' that will be garbage";
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
const Expr *receiver = ME->getReceiver();
report->addRange(receiver->getSourceRange());
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
receiver);
C.EmitReport(report);
C.EmitReport(report);
}
static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
@ -188,11 +281,11 @@ static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
const GRState *state,
const ObjCMessageExpr *ME) {
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
QualType RetTy = ME->getType();
ASTContext &Ctx = C.getASTContext();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
@ -216,7 +309,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
if (CanRetTy != Ctx.VoidTy &&
C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
// Compute: sizeof(void *) and sizeof(return type)
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
if (voidPtrSize < returnTypeSize &&
@ -247,6 +340,6 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
C.GenerateNode(state->BindExpr(ME, V));
return;
}
C.addTransition(state);
}

View File

@ -220,16 +220,25 @@ public:
if (E->isConstantInitializer(Ctx))
return;
// Special case: check for initializations from constant
// variables.
//
// e.g. extern const int MyConstant;
// int x = MyConstant;
//
if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
// Special case: check for initialization from constant
// variables.
//
// e.g. extern const int MyConstant;
// int x = MyConstant;
//
if (VD->hasGlobalStorage() &&
VD->getType().isConstQualified()) return;
VD->getType().isConstQualified())
return;
// Special case: check for initialization from scalar
// parameters. This is often a form of defensive
// programming. Non-scalars are still an error since
// because it more likely represents an actual algorithmic
// bug.
if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
return;
}
Report(V, DeadInit, V->getLocation(), E->getSourceRange());
}

View File

@ -44,7 +44,9 @@ public:
}
SVal ArrayToPointer(Loc Array);
Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
Store RemoveDeadBindings(Store store, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){
return store;
}

View File

@ -481,7 +481,9 @@ void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
SymbolReaper SymReaper(BasePred->getLocationContext(), SymMgr);
CleanedState = AMgr.shouldPurgeDead()
? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, SymReaper)
? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt,
BasePred->getLocationContext()->getCurrentStackFrame(),
SymReaper)
: EntryNode->getState();
// Process any special transfer function for dead symbols.

View File

@ -35,6 +35,7 @@ GRStateManager::~GRStateManager() {
const GRState*
GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper) {
// This code essentially performs a "mark-and-sweep" of the VariableBindings.
@ -50,7 +51,7 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
state, RegionRoots);
// Clean up the store.
NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, SymReaper,
NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, LCtx, SymReaper,
RegionRoots);
return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState),

View File

@ -354,7 +354,9 @@ public: // Part of public interface to class.
/// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed.
Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
Store RemoveDeadBindings(Store store, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
const GRState *EnterStackFrame(const GRState *state,
@ -1678,12 +1680,14 @@ class RemoveDeadBindingsWorker :
llvm::SmallVector<const SymbolicRegion*, 12> Postponed;
SymbolReaper &SymReaper;
Stmt *Loc;
const StackFrameContext *CurrentLCtx;
public:
RemoveDeadBindingsWorker(RegionStoreManager &rm, GRStateManager &stateMgr,
RegionBindings b, SymbolReaper &symReaper,
Stmt *loc)
Stmt *loc, const StackFrameContext *LCtx)
: ClusterAnalysis<RemoveDeadBindingsWorker>(rm, stateMgr, b),
SymReaper(symReaper), Loc(loc) {}
SymReaper(symReaper), Loc(loc), CurrentLCtx(LCtx) {}
// Called by ClusterAnalysis.
void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C);
@ -1713,6 +1717,15 @@ void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
return;
}
// CXXThisRegion in the current or parent location context is live.
if (const CXXThisRegion *TR = dyn_cast<CXXThisRegion>(baseR)) {
const StackArgumentsSpaceRegion *StackReg =
cast<StackArgumentsSpaceRegion>(TR->getSuperRegion());
const StackFrameContext *RegCtx = StackReg->getStackFrame();
if (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx))
AddToWorkList(TR, C);
}
}
void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
@ -1799,11 +1812,12 @@ bool RemoveDeadBindingsWorker::UpdatePostponed() {
}
Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
RegionBindings B = GetRegionBindings(store);
RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc);
RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc, LCtx);
W.GenerateClusters();
// Enqueue the region roots onto the worklist.

View File

@ -25,17 +25,47 @@ using namespace clang;
using namespace CodeGen;
using namespace llvm;
static void EmitMemoryBarrier(CodeGenFunction &CGF,
bool LoadLoad, bool LoadStore,
bool StoreLoad, bool StoreStore,
bool Device) {
Value *True = llvm::ConstantInt::getTrue(CGF.getLLVMContext());
Value *False = llvm::ConstantInt::getFalse(CGF.getLLVMContext());
Value *C[5] = { LoadLoad ? True : False,
LoadStore ? True : False,
StoreLoad ? True : False,
StoreStore ? True : False,
Device ? True : False };
CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::memory_barrier),
C, C + 5);
}
// The atomic builtins are also full memory barriers. This is a utility for
// wrapping a call to the builtins with memory barriers.
static Value *EmitCallWithBarrier(CodeGenFunction &CGF, Value *Fn,
Value **ArgBegin, Value **ArgEnd) {
// FIXME: We need a target hook for whether this applies to device memory or
// not.
bool Device = true;
// Create barriers both before and after the call.
EmitMemoryBarrier(CGF, true, true, true, true, Device);
Value *Result = CGF.Builder.CreateCall(Fn, ArgBegin, ArgEnd);
EmitMemoryBarrier(CGF, true, true, true, true, Device);
return Result;
}
/// Utility to insert an atomic instruction based on Instrinsic::ID
/// and the expression node.
static RValue EmitBinaryAtomic(CodeGenFunction& CGF,
static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
Intrinsic::ID Id, const CallExpr *E) {
Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
CGF.EmitScalarExpr(E->getArg(1)) };
const llvm::Type *ResType[2];
ResType[0] = CGF.ConvertType(E->getType());
ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
return RValue::get(CGF.Builder.CreateCall2(AtomF,
CGF.EmitScalarExpr(E->getArg(0)),
CGF.EmitScalarExpr(E->getArg(1))));
return RValue::get(EmitCallWithBarrier(CGF, AtomF, Args, Args + 2));
}
/// Utility to insert an atomic instruction based Instrinsic::ID and
@ -48,15 +78,14 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF,
ResType[0] = CGF.ConvertType(E->getType());
ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
Value *Ptr = CGF.EmitScalarExpr(E->getArg(0));
Value *Operand = CGF.EmitScalarExpr(E->getArg(1));
Value *Result = CGF.Builder.CreateCall2(AtomF, Ptr, Operand);
Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
CGF.EmitScalarExpr(E->getArg(1)) };
Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2);
if (Id == Intrinsic::atomic_load_nand)
Result = CGF.Builder.CreateNot(Result);
return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Operand));
return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Args[1]));
}
static llvm::ConstantInt *getInt32(llvm::LLVMContext &Context, int32_t Value) {
@ -585,33 +614,31 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_val_compare_and_swap_2:
case Builtin::BI__sync_val_compare_and_swap_4:
case Builtin::BI__sync_val_compare_and_swap_8:
case Builtin::BI__sync_val_compare_and_swap_16:
{
case Builtin::BI__sync_val_compare_and_swap_16: {
const llvm::Type *ResType[2];
ResType[0]= ConvertType(E->getType());
ResType[1] = ConvertType(E->getArg(0)->getType());
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
return RValue::get(Builder.CreateCall3(AtomF,
EmitScalarExpr(E->getArg(0)),
EmitScalarExpr(E->getArg(1)),
EmitScalarExpr(E->getArg(2))));
Value *Args[3] = { EmitScalarExpr(E->getArg(0)),
EmitScalarExpr(E->getArg(1)),
EmitScalarExpr(E->getArg(2)) };
return RValue::get(EmitCallWithBarrier(*this, AtomF, Args, Args + 3));
}
case Builtin::BI__sync_bool_compare_and_swap_1:
case Builtin::BI__sync_bool_compare_and_swap_2:
case Builtin::BI__sync_bool_compare_and_swap_4:
case Builtin::BI__sync_bool_compare_and_swap_8:
case Builtin::BI__sync_bool_compare_and_swap_16:
{
case Builtin::BI__sync_bool_compare_and_swap_16: {
const llvm::Type *ResType[2];
ResType[0]= ConvertType(E->getArg(1)->getType());
ResType[1] = llvm::PointerType::getUnqual(ResType[0]);
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
Value *OldVal = EmitScalarExpr(E->getArg(1));
Value *PrevVal = Builder.CreateCall3(AtomF,
EmitScalarExpr(E->getArg(0)),
OldVal,
EmitScalarExpr(E->getArg(2)));
Value *Args[3] = { EmitScalarExpr(E->getArg(0)),
OldVal,
EmitScalarExpr(E->getArg(2)) };
Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args, Args + 3);
Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal);
// zext bool to int.
return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType())));
@ -623,6 +650,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_lock_test_and_set_8:
case Builtin::BI__sync_lock_test_and_set_16:
return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E);
case Builtin::BI__sync_lock_release_1:
case Builtin::BI__sync_lock_release_2:
case Builtin::BI__sync_lock_release_4:
@ -638,10 +666,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI__sync_synchronize: {
Value *C[5];
C[0] = C[1] = C[2] = C[3] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 1);
C[4] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0);
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5);
// We assume like gcc appears to, that this only applies to cached memory.
EmitMemoryBarrier(*this, true, true, true, true, false);
return RValue::get(0);
}

View File

@ -165,19 +165,21 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule());
// Switch any previous uses to the alias.
const char *MangledName = getMangledName(AliasDecl);
llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
MangleBuffer MangledName;
getMangledName(MangledName, AliasDecl);
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
assert(Entry->isDeclaration() && "definition already exists for alias");
assert(Entry->getType() == AliasType &&
"declaration exists with different type");
Alias->takeName(Entry);
Entry->replaceAllUsesWith(Alias);
Entry->eraseFromParent();
} else {
Alias->setName(MangledName.getString());
}
Entry = Alias;
// Finally, set up the alias with its proper name and attributes.
Alias->setName(MangledName);
SetCommonAttributes(AliasDecl.getDecl(), Alias);
return false;
@ -214,8 +216,9 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
llvm::GlobalValue *
CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
CXXCtorType Type) {
const char *Name = getMangledCXXCtorName(D, Type);
if (llvm::GlobalValue *V = GlobalDeclMap[Name])
MangleBuffer Name;
getMangledCXXCtorName(Name, D, Type);
if (llvm::GlobalValue *V = GetGlobalValue(Name))
return V;
const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
@ -226,13 +229,10 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type)));
}
const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
CXXCtorType Type) {
llvm::SmallString<256> Name;
getMangleContext().mangleCXXCtor(D, Type, Name);
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
void CodeGenModule::getMangledCXXCtorName(MangleBuffer &Name,
const CXXConstructorDecl *D,
CXXCtorType Type) {
getMangleContext().mangleCXXCtor(D, Type, Name.getBuffer());
}
void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
@ -279,8 +279,9 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
llvm::GlobalValue *
CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type) {
const char *Name = getMangledCXXDtorName(D, Type);
if (llvm::GlobalValue *V = GlobalDeclMap[Name])
MangleBuffer Name;
getMangledCXXDtorName(Name, D, Type);
if (llvm::GlobalValue *V = GetGlobalValue(Name))
return V;
const llvm::FunctionType *FTy =
@ -290,13 +291,10 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type)));
}
const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D,
CXXDtorType Type) {
llvm::SmallString<256> Name;
getMangleContext().mangleCXXDtor(D, Type, Name);
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name,
const CXXDestructorDecl *D,
CXXDtorType Type) {
getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer());
}
llvm::Constant *
@ -470,12 +468,10 @@ CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
OutName);
else
getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
OutName += '\0';
const char* Name = UniqueMangledName(OutName.begin(), OutName.end());
// Get function for mangled name
const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
return GetOrCreateLLVMFunction(OutName, Ty, GlobalDecl());
}
llvm::Constant *
@ -484,10 +480,8 @@ CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD,
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
// Compute mangled name
llvm::SmallString<256> OutName;
getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName);
OutName += '\0';
const char* Name = UniqueMangledName(OutName.begin(), OutName.end());
llvm::SmallString<256> Name;
getMangleContext().mangleCovariantThunk(MD, Adjustment, Name);
// Get function for mangled name
const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
@ -528,9 +522,6 @@ void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) {
llvm::Constant *SubExpr =
cast<llvm::ConstantExpr>(FnConst)->getOperand(0);
llvm::Function *OldFn = cast<llvm::Function>(SubExpr);
std::string Name = OldFn->getNameStr();
GlobalDeclMap.erase(UniqueMangledName(Name.data(),
Name.data() + Name.size() + 1));
llvm::Constant *NewFnConst;
if (!ReturnAdjustment.isEmpty())
NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj);

View File

@ -104,12 +104,20 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
void CGDebugInfo::CreateCompileUnit() {
// Get absolute path name.
SourceManager &SM = CGM.getContext().getSourceManager();
std::string MainFileName = CGM.getCodeGenOpts().MainFileName;
if (MainFileName.empty())
MainFileName = "<unknown>";
llvm::sys::Path AbsFileName(MainFileName);
AbsFileName.makeAbsolute();
std::string MainFileDir;
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID()))
MainFileDir = MainFile->getDir()->getName();
else
MainFileDir = AbsFileName.getDirname();
unsigned LangTag;
const LangOptions &LO = CGM.getLangOptions();
if (LO.CPlusPlus) {
@ -138,7 +146,7 @@ void CGDebugInfo::CreateCompileUnit() {
// Create new compile unit.
TheCU = DebugFactory.CreateCompileUnit(
LangTag, AbsFileName.getLast(), AbsFileName.getDirname(), Producer, true,
LangTag, AbsFileName.getLast(), MainFileDir, Producer, true,
LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
}
@ -561,13 +569,13 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
llvm::StringRef MethodName = getFunctionName(Method);
llvm::StringRef MethodLinkageName;
llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit);
// Since a single ctor/dtor corresponds to multiple functions, it doesn't
// make sense to give a single ctor/dtor a linkage name.
MangleBuffer MethodLinkageName;
if (!IsCtorOrDtor)
MethodLinkageName = CGM.getMangledName(Method);
CGM.getMangledName(MethodLinkageName, Method);
SourceManager &SM = CGM.getContext().getSourceManager();
@ -1299,7 +1307,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
CGBuilderTy &Builder) {
llvm::StringRef Name;
llvm::StringRef LinkageName;
MangleBuffer LinkageName;
const Decl *D = GD.getDecl();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
@ -1318,11 +1326,11 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
// Use mangled name as linkage name for c/c++ functions.
LinkageName = CGM.getMangledName(GD);
CGM.getMangledName(LinkageName, GD);
} else {
// Use llvm function name as linkage name.
Name = Fn->getName();
LinkageName = Name;
LinkageName.setString(Name);
if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
}

View File

@ -103,13 +103,18 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) {
static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
const char *Separator) {
CodeGenModule &CGM = CGF.CGM;
if (CGF.getContext().getLangOptions().CPlusPlus)
return CGM.getMangledName(&D);
if (CGF.getContext().getLangOptions().CPlusPlus) {
MangleBuffer Name;
CGM.getMangledName(Name, &D);
return Name.getString().str();
}
std::string ContextName;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl))
ContextName = CGM.getMangledName(FD);
else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) {
MangleBuffer Name;
CGM.getMangledName(Name, FD);
ContextName = Name.getString().str();
} else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
ContextName = CGF.CurFn->getName();
else
// FIXME: What about in a block??

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
#include "clang/CodeGen/CodeGenOptions.h"
using namespace clang;
using namespace CodeGen;
@ -64,7 +65,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
} else
DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
}
@ -92,6 +93,12 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
void
CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Constant *DeclPtr) {
// Generate a global destructor entry if not using __cxa_atexit.
if (!CGM.getCodeGenOpts().CXAAtExit) {
CGM.AddCXXDtorEntry(DtorFn, DeclPtr);
return;
}
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
@ -150,10 +157,9 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
false);
// Create our global initialization function.
// FIXME: Should this be tweakable by targets?
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
"__cxx_global_initialization", &TheModule);
"_GLOBAL__I_a", &TheModule);
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
&CXXGlobalInits[0],
@ -161,6 +167,28 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
AddGlobalCtor(Fn);
}
void CodeGenModule::AddCXXDtorEntry(llvm::Constant *DtorFn,
llvm::Constant *Object) {
CXXGlobalDtors.push_back(std::make_pair(DtorFn, Object));
}
void CodeGenModule::EmitCXXGlobalDtorFunc() {
if (CXXGlobalDtors.empty())
return;
const llvm::FunctionType *FTy
= llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
false);
// Create our global destructor function.
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
"_GLOBAL__D_a", &TheModule);
CodeGenFunction(*this).GenerateCXXGlobalDtorFunc(Fn, CXXGlobalDtors);
AddGlobalDtor(Fn);
}
void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
@ -184,6 +212,20 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
FinishFunction();
}
void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::Constant*, llvm::Constant*> >
&DtorsAndObjects) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
SourceLocation());
// Emit the dtors, in reverse order from construction.
for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i)
Builder.CreateCall(DtorsAndObjects[e - i - 1].first,
DtorsAndObjects[e - i - 1].second);
FinishFunction();
}
static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) {
// int __cxa_guard_acquire(__int64_t *guard_object);

View File

@ -486,8 +486,6 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
llvm::SmallVector<llvm::Value*, 8> Args;
Args.clear();
SelectorArgs.push_back(Exc);
SelectorArgs.push_back(Personality);
@ -584,12 +582,11 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even
// though we don't use the result.
Args.clear();
Args.push_back(Exc);
Args.push_back(Personality);
Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
0));
Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
llvm::Value *Args[] = {
Exc, Personality,
llvm::ConstantInt::getNullValue(llvm::Type::getInt32Ty(VMContext))
};
Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
Builder.CreateStore(Exc, RethrowPtr);
EmitBranchThroughCleanup(FinallyRethrow);
@ -600,7 +597,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
Builder.CreateInvoke(getEndCatchFn(*this),
Cont, TerminateHandler,
Args.begin(), Args.begin());
&Args[0], &Args[0]);
EmitBlock(Cont);
if (Info.SwitchBlock)
EmitBlock(Info.SwitchBlock);
@ -677,12 +674,8 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
// C string type. Used in lots of places.
PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
llvm::SmallVector<llvm::Value*, 8> Args;
Args.clear();
Args.push_back(Exc);
Args.push_back(Personality);
Args.push_back(Null);
CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
llvm::Value *Args[] = { Exc, Personality, Null };
CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
CGF.EmitBlock(CleanupEntryBB);
@ -731,12 +724,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even
// though we don't use the result.
llvm::SmallVector<llvm::Value*, 8> Args;
Args.push_back(Exc);
Args.push_back(Personality);
Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
1));
Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
llvm::Value *Args[] = {
Exc, Personality,
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)
};
Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
llvm::CallInst *TerminateCall =
Builder.CreateCall(getTerminateFn(*this));
TerminateCall->setDoesNotReturn();

View File

@ -1634,7 +1634,7 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCCategoryImplDecl *OCD =
dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
std::string CategoryName = OCD ? OCD->getNameAsString() : "";
std::string ClassName = OMD->getClassInterface()->getNameAsString();
std::string ClassName = CD->getName();
std::string MethodName = OMD->getSelector().getAsString();
bool isClassMethod = !OMD->isInstanceMethod();

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
#include <algorithm>
#include <cstdio>
using namespace clang;
@ -1147,6 +1148,12 @@ private:
ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
friend bool operator==(const ReturnAdjustment &LHS,
const ReturnAdjustment &RHS) {
return LHS.NonVirtual == RHS.NonVirtual &&
LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
}
};
/// MethodInfo - Contains information about a method in a vtable.
@ -1191,6 +1198,12 @@ private:
ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { }
bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; }
friend bool operator==(const ThisAdjustment &LHS,
const ThisAdjustment &RHS) {
return LHS.NonVirtual == RHS.NonVirtual &&
LHS.VCallOffsetOffset == RHS.VCallOffsetOffset;
}
};
/// ThunkInfo - The 'this' pointer adjustment as well as an optional return
@ -1206,8 +1219,12 @@ private:
ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
: This(This), Return(Return) { }
bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
return LHS.This == RHS.This && LHS.Return == RHS.Return;
}
bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
};
typedef llvm::DenseMap<uint64_t, ThunkInfo> ThunksInfoMapTy;
@ -1215,6 +1232,16 @@ private:
/// Thunks - The thunks by vtable index in the vtable currently being built.
ThunksInfoMapTy Thunks;
typedef llvm::DenseMap<const CXXMethodDecl *,
llvm::SmallVector<ThunkInfo, 1> > MethodThunksMapTy;
/// MethodThunks - A map that contains all the thunks needed for all methods
/// in the vtable currently being built.
MethodThunksMapTy MethodThunks;
/// AddThunk - Add a thunk for the given method.
void AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk);
/// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
/// part of the vtable we're currently building.
void ComputeThisAdjustments();
@ -1330,6 +1357,20 @@ public:
void dumpLayout(llvm::raw_ostream&);
};
void VtableBuilder::AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk) {
if (isBuildingConstructorVtable())
return;
llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD];
// Check if we have this thunk already.
if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
ThunksVector.end())
return;
ThunksVector.push_back(Thunk);
}
/// OverridesMethodInBases - Checks whether whether this virtual member
/// function overrides a member function in any of the given bases.
/// Returns the overridden member function, or null if none was found.
@ -1382,6 +1423,8 @@ void VtableBuilder::ComputeThisAdjustments() {
// Add an adjustment for the deleting destructor as well.
Thunks[VtableIndex + 1].This = ThisAdjustment;
}
AddThunk(Overrider.Method, Thunks[VtableIndex]);
}
/// Clear the method info map.
@ -2182,20 +2225,25 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << '\n';
if (!isBuildingConstructorVtable() && MostDerivedClass->getNumVBases()) {
Out << "Virtual base offset offsets for '";
Out << MostDerivedClass->getQualifiedNameAsString() << "'.\n";
if (isBuildingConstructorVtable())
return;
if (MostDerivedClass->getNumVBases()) {
// We store the virtual base class names and their offsets in a map to get
// a stable order.
std::map<std::string, int64_t> ClassNamesAndOffsets;
std::map<std::string, int64_t> ClassNamesAndOffsets;
for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(),
E = VBaseOffsetOffsets.end(); I != E; ++I) {
std::string ClassName = I->first->getQualifiedNameAsString();
int64_t OffsetOffset = I->second;
ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset));
}
Out << "Virtual base offset offsets for '";
Out << MostDerivedClass->getQualifiedNameAsString() << "' (";
Out << ClassNamesAndOffsets.size();
Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n";
for (std::map<std::string, int64_t>::const_iterator I =
ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end();
@ -2204,6 +2252,52 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << "\n";
}
if (!MethodThunks.empty()) {
// We store the method names in a map to get a stable order.
std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
for (MethodThunksMapTy::const_iterator I = MethodThunks.begin(),
E = MethodThunks.end(); I != E; ++I) {
const CXXMethodDecl *MD = I->first;
std::string MethodName =
PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
MD);
MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
}
for (std::map<std::string, const CXXMethodDecl *>::const_iterator I =
MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end();
I != E; ++I) {
const std::string &MethodName = I->first;
const CXXMethodDecl *MD = I->second;
const llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD];
Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
const ThunkInfo &Thunk = ThunksVector[I];
Out << llvm::format("%4d | ", I);
// If this function pointer has a 'this' pointer adjustment, dump it.
if (!Thunk.This.isEmpty()) {
Out << "this: ";
Out << Thunk.This.NonVirtual << " nv";
if (Thunk.This.VCallOffsetOffset) {
Out << ", " << Thunk.This.VCallOffsetOffset;
Out << " v";
}
}
Out << '\n';
}
}
}
}
}

View File

@ -1231,6 +1231,12 @@ public:
llvm::Constant **Decls,
unsigned NumDecls);
/// GenerateCXXGlobalDtorFunc - Generates code for destroying global
/// variables.
void GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::Constant*,
llvm::Constant*> > &DtorsAndObjects);
void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D);
void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);

View File

@ -81,6 +81,7 @@ void CodeGenModule::createObjCRuntime() {
void CodeGenModule::Release() {
EmitDeferred();
EmitCXXGlobalInitFunc();
EmitCXXGlobalDtorFunc();
if (Runtime)
if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction())
AddGlobalCtor(ObjCInitFunction);
@ -163,15 +164,15 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
}
}
const char *CodeGenModule::getMangledName(const GlobalDecl &GD) {
void CodeGenModule::getMangledName(MangleBuffer &Buffer, GlobalDecl GD) {
const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
if (const CXXConstructorDecl *D = dyn_cast<CXXConstructorDecl>(ND))
return getMangledCXXCtorName(D, GD.getCtorType());
return getMangledCXXCtorName(Buffer, D, GD.getCtorType());
if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(ND))
return getMangledCXXDtorName(D, GD.getDtorType());
return getMangledCXXDtorName(Buffer, D, GD.getDtorType());
return getMangledName(ND);
return getMangledName(Buffer, ND);
}
/// \brief Retrieves the mangled name for the given declaration.
@ -180,23 +181,19 @@ const char *CodeGenModule::getMangledName(const GlobalDecl &GD) {
/// const char* containing the mangled name. Otherwise, returns
/// the unmangled name.
///
const char *CodeGenModule::getMangledName(const NamedDecl *ND) {
void CodeGenModule::getMangledName(MangleBuffer &Buffer,
const NamedDecl *ND) {
if (!getMangleContext().shouldMangleDeclName(ND)) {
assert(ND->getIdentifier() && "Attempt to mangle unnamed decl.");
return ND->getNameAsCString();
Buffer.setString(ND->getNameAsCString());
return;
}
llvm::SmallString<256> Name;
getMangleContext().mangleName(ND, Name);
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
getMangleContext().mangleName(ND, Buffer.getBuffer());
}
const char *CodeGenModule::UniqueMangledName(const char *NameStart,
const char *NameEnd) {
assert(*(NameEnd - 1) == '\0' && "Mangled name must be null terminated!");
return MangledNames.GetOrCreateValue(NameStart, NameEnd).getKeyData();
llvm::GlobalValue *CodeGenModule::GetGlobalValue(llvm::StringRef Name) {
return getModule().getNamedValue(Name);
}
/// AddGlobalCtor - Add a function to the list that will be called before
@ -505,11 +502,12 @@ void CodeGenModule::EmitDeferred() {
GlobalDecl D = DeferredDeclsToEmit.back();
DeferredDeclsToEmit.pop_back();
// The mangled name for the decl must have been emitted in GlobalDeclMap.
// Look it up to see if it was defined with a stronger definition (e.g. an
// extern inline function with a strong function redefinition). If so,
// just ignore the deferred decl.
llvm::GlobalValue *CGRef = GlobalDeclMap[getMangledName(D)];
MangleBuffer Name;
getMangledName(Name, D);
llvm::GlobalValue *CGRef = GetGlobalValue(Name);
assert(CGRef && "Deferred decl wasn't referenced?");
if (!CGRef->isDeclaration())
@ -644,18 +642,14 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType());
// Unique the name through the identifier table.
const char *AliaseeName =
getContext().Idents.get(AA->getAliasee()).getNameStart();
// See if there is already something with the target's name in the module.
llvm::GlobalValue *Entry = GlobalDeclMap[AliaseeName];
llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee());
llvm::Constant *Aliasee;
if (isa<llvm::FunctionType>(DeclTy))
Aliasee = GetOrCreateLLVMFunction(AliaseeName, DeclTy, GlobalDecl());
Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl());
else
Aliasee = GetOrCreateLLVMGlobal(AliaseeName,
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
llvm::PointerType::getUnqual(DeclTy), 0);
if (!Entry) {
llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee);
@ -676,7 +670,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// If this is an alias definition (which otherwise looks like a declaration)
// emit it now.
if (Global->hasAttr<AliasAttr>())
return EmitAliasDefinition(Global);
return EmitAliasDefinition(GD);
// Ignore declarations, they will be emitted on their first use.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
@ -696,8 +690,9 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
if (MayDeferGeneration(Global)) {
// If the value has already been used, add it directly to the
// DeferredDeclsToEmit list.
const char *MangledName = getMangledName(GD);
if (GlobalDeclMap.count(MangledName))
MangleBuffer MangledName;
getMangledName(MangledName, GD);
if (GetGlobalValue(MangledName))
DeferredDeclsToEmit.push_back(GD);
else {
// Otherwise, remember that we saw a deferred decl with this name. The
@ -753,11 +748,12 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
///
/// If D is non-null, it specifies a decl that correspond to this. This is used
/// to set the attributes on the function when it is first created.
llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
const llvm::Type *Ty,
GlobalDecl D) {
llvm::Constant *
CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
const llvm::Type *Ty,
GlobalDecl D) {
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
if (WeakRefReferences.count(Entry)) {
const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl());
@ -786,17 +782,15 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
}
llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
llvm::Function::ExternalLinkage,
"", &getModule());
F->setName(MangledName);
MangledName, &getModule());
assert(F->getName() == MangledName && "name was uniqued!");
if (D.getDecl())
SetFunctionAttributes(D, F, IsIncompleteFunction);
Entry = F;
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
// of the file.
llvm::DenseMap<const char*, GlobalDecl>::iterator DDI =
DeferredDecls.find(MangledName);
llvm::StringMap<GlobalDecl>::iterator DDI = DeferredDecls.find(MangledName);
if (DDI != DeferredDecls.end()) {
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
// list, and remove it from DeferredDecls (since we don't need it anymore).
@ -839,16 +833,16 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
// If there was no specific requested type, just convert it now.
if (!Ty)
Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType());
return GetOrCreateLLVMFunction(getMangledName(GD), Ty, GD);
MangleBuffer MangledName;
getMangledName(MangledName, GD);
return GetOrCreateLLVMFunction(MangledName, Ty, GD);
}
/// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name.
llvm::Constant *
CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
const char *Name) {
// Convert Name to be a uniqued string from the IdentifierInfo table.
Name = getContext().Idents.get(Name).getNameStart();
llvm::StringRef Name) {
return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl());
}
@ -870,11 +864,12 @@ static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) {
///
/// If D is non-null, it specifies a decl that correspond to this. This is used
/// to set the attributes on the global when it is first created.
llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
const llvm::PointerType*Ty,
const VarDecl *D) {
llvm::Constant *
CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
const llvm::PointerType *Ty,
const VarDecl *D) {
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
if (WeakRefReferences.count(Entry)) {
if (D && !D->hasAttr<WeakAttr>())
@ -893,8 +888,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
// of the file.
llvm::DenseMap<const char*, GlobalDecl>::iterator DDI =
DeferredDecls.find(MangledName);
llvm::StringMap<GlobalDecl>::iterator DDI = DeferredDecls.find(MangledName);
if (DDI != DeferredDecls.end()) {
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
// list, and remove it from DeferredDecls (since we don't need it anymore).
@ -905,9 +899,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(getModule(), Ty->getElementType(), false,
llvm::GlobalValue::ExternalLinkage,
0, "", 0,
0, MangledName, 0,
false, Ty->getAddressSpace());
GV->setName(MangledName);
// Handle things which are present even on external declarations.
if (D) {
@ -926,7 +919,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
GV->setThreadLocal(D->isThreadSpecified());
}
return Entry = GV;
return GV;
}
@ -943,16 +936,17 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
const llvm::PointerType *PTy =
llvm::PointerType::get(Ty, ASTTy.getAddressSpace());
return GetOrCreateLLVMGlobal(getMangledName(D), PTy, D);
MangleBuffer MangledName;
getMangledName(MangledName, D);
return GetOrCreateLLVMGlobal(MangledName, PTy, D);
}
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *
CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty,
const char *Name) {
// Convert Name to be a uniqued string from the IdentifierInfo table.
Name = getContext().Idents.get(Name).getNameStart();
llvm::StringRef Name) {
return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0);
}
@ -963,8 +957,9 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
// If we have not seen a reference to this variable yet, place it
// into the deferred declarations table to be emitted if needed
// later.
const char *MangledName = getMangledName(D);
if (GlobalDeclMap.count(MangledName) == 0) {
MangleBuffer MangledName;
getMangledName(MangledName, D);
if (!GetGlobalValue(MangledName)) {
DeferredDecls[MangledName] = D;
return;
}
@ -1133,12 +1128,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->getType()->getElementType() != InitType ||
GV->getType()->getAddressSpace() != ASTTy.getAddressSpace()) {
// Remove the old entry from GlobalDeclMap so that we'll create a new one.
GlobalDeclMap.erase(getMangledName(D));
// Move the old entry aside so that we'll create a new one.
Entry->setName(llvm::StringRef());
// Make a new global with the correct type, this is now guaranteed to work.
GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(D, InitType));
GV->takeName(cast<llvm::GlobalValue>(Entry));
// Replace all uses of the old global with the new global
llvm::Constant *NewPtrForOldDecl =
@ -1296,11 +1290,10 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
//
// This happens if there is a prototype for a function
// (e.g. "int f()") and then a definition of a different type
// (e.g. "int f(int x)"). Start by making a new function of the
// correct type, RAUW, then steal the name.
GlobalDeclMap.erase(getMangledName(D));
// (e.g. "int f(int x)"). Move the old function aside so that it
// doesn't interfere with GetAddrOfFunction.
OldFn->setName(llvm::StringRef());
llvm::Function *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty));
NewFn->takeName(OldFn);
// If this is an implementation of a function without a prototype, try to
// replace any existing uses of the function (which may be calls) with uses
@ -1336,23 +1329,29 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
AddGlobalDtor(Fn, DA->getPriority());
}
void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
const AliasAttr *AA = D->getAttr<AliasAttr>();
assert(AA && "Not an alias?");
const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
MangleBuffer MangledName;
getMangledName(MangledName, GD);
// Unique the name through the identifier table.
const char *AliaseeName =
getContext().Idents.get(AA->getAliasee()).getNameStart();
// If there is a definition in the module, then it wins over the alias.
// This is dubious, but allow it to be safe. Just ignore the alias.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry && !Entry->isDeclaration())
return;
const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
// Create a reference to the named value. This ensures that it is emitted
// if a deferred decl.
llvm::Constant *Aliasee;
if (isa<llvm::FunctionType>(DeclTy))
Aliasee = GetOrCreateLLVMFunction(AliaseeName, DeclTy, GlobalDecl());
Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl());
else
Aliasee = GetOrCreateLLVMGlobal(AliaseeName,
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
llvm::PointerType::getUnqual(DeclTy), 0);
// Create the new alias itself, but don't set a name yet.
@ -1361,18 +1360,9 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
llvm::Function::ExternalLinkage,
"", Aliasee, &getModule());
// See if there is already something with the alias' name in the module.
const char *MangledName = getMangledName(D);
llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
if (Entry && !Entry->isDeclaration()) {
// If there is a definition in the module, then it wins over the alias.
// This is dubious, but allow it to be safe. Just ignore the alias.
GA->eraseFromParent();
return;
}
if (Entry) {
assert(Entry->isDeclaration());
// If there is a declaration in the module, then we had an extern followed
// by the alias, as in:
// extern int test6();
@ -1380,16 +1370,15 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
// int test6() __attribute__((alias("test7")));
//
// Remove it and replace uses of it with the alias.
GA->takeName(Entry);
Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GA,
Entry->getType()));
Entry->eraseFromParent();
} else {
GA->setName(MangledName.getString());
}
// Now we know that there is no conflict, set the name.
Entry = GA;
GA->setName(MangledName);
// Set attributes which are particular to an alias; this is a
// specialization of the attributes which may be set on a global
// variable/function.
@ -1426,8 +1415,6 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
const llvm::FunctionType *Ty =
cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
// Unique the name through the identifier table.
Name = getContext().Idents.get(Name).getNameStart();
return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD));
}

View File

@ -73,7 +73,7 @@ namespace CodeGen {
class CodeGenFunction;
class CGDebugInfo;
class CGObjCRuntime;
class MangleBuffer;
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
@ -103,38 +103,16 @@ class CodeGenModule : public BlockModule {
llvm::Function *MemMoveFn;
llvm::Function *MemSetFn;
/// GlobalDeclMap - Mapping of decl names (represented as unique
/// character pointers from either the identifier table or the set
/// of mangled names) to global variables we have already
/// emitted. Note that the entries in this map are the actual
/// globals and therefore may not be of the same type as the decl,
/// they should be bitcasted on retrieval. Also note that the
/// globals are keyed on their source mangled name, not the global name
/// (which may change with attributes such as asm-labels). The key
/// to this map should be generated using getMangledName().
///
/// Note that this map always lines up exactly with the contents of the LLVM
/// IR symbol table, but this is quicker to query since it is doing uniqued
/// pointer lookups instead of full string lookups.
llvm::DenseMap<const char*, llvm::GlobalValue*> GlobalDeclMap;
// WeakRefReferences - A set of references that have only been seen via
// a weakref so far. This is used to remove the weak of the reference if we ever
// see a direct reference or a definition.
llvm::SmallPtrSet<llvm::GlobalValue*, 10> WeakRefReferences;
/// \brief Contains the strings used for mangled names.
///
/// FIXME: Eventually, this should map from the semantic/canonical
/// declaration for each global entity to its mangled name (if it
/// has one).
llvm::StringSet<> MangledNames;
/// DeferredDecls - This contains all the decls which have definitions but
/// which are deferred for emission and therefore should only be output if
/// they are actually used. If a decl is in this, then it is known to have
/// not been referenced yet. The key to this map is a uniqued mangled name.
llvm::DenseMap<const char*, GlobalDecl> DeferredDecls;
/// not been referenced yet.
llvm::StringMap<GlobalDecl> DeferredDecls;
/// DeferredDeclsToEmit - This is a list of deferred decls which we have seen
/// that *are* actually referenced. These get code generated when the module
@ -160,10 +138,14 @@ class CodeGenModule : public BlockModule {
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
llvm::StringMap<llvm::Constant*> ConstantStringMap;
/// CXXGlobalInits - Variables with global initializers that need to run
/// CXXGlobalInits - Global variables with initializers that need to run
/// before main.
std::vector<llvm::Constant*> CXXGlobalInits;
/// CXXGlobalDtors - Global destructor functions and arguments that need to
/// run on termination.
std::vector<std::pair<llvm::Constant*,llvm::Constant*> > CXXGlobalDtors;
/// CFConstantStringClassRef - Cached reference to the class for constant
/// strings. This value has type int * but is actually an Obj-C class pointer.
llvm::Constant *CFConstantStringClassRef;
@ -343,14 +325,18 @@ public:
void AddAnnotation(llvm::Constant *C) { Annotations.push_back(C); }
/// AddCXXDtorEntry - Add a destructor and object to add to the C++ global
/// destructor function.
void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object);
/// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name.
llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty,
const char *Name);
llvm::StringRef Name);
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty,
const char *Name);
llvm::StringRef Name);
void UpdateCompletedType(const TagDecl *TD) {
// Make sure that this type is translated.
@ -422,13 +408,14 @@ public:
AttributeListType &PAL,
unsigned &CallingConv);
const char *getMangledName(const GlobalDecl &D);
const char *getMangledName(const NamedDecl *ND);
const char *getMangledCXXCtorName(const CXXConstructorDecl *D,
CXXCtorType Type);
const char *getMangledCXXDtorName(const CXXDestructorDecl *D,
CXXDtorType Type);
void getMangledName(MangleBuffer &Buffer, GlobalDecl D);
void getMangledName(MangleBuffer &Buffer, const NamedDecl *ND);
void getMangledCXXCtorName(MangleBuffer &Buffer,
const CXXConstructorDecl *D,
CXXCtorType Type);
void getMangledCXXDtorName(MangleBuffer &Buffer,
const CXXDestructorDecl *D,
CXXDtorType Type);
void EmitTentativeDefinition(const VarDecl *D);
@ -456,14 +443,12 @@ public:
std::vector<const CXXRecordDecl*> DeferredVtables;
private:
/// UniqueMangledName - Unique a name by (if necessary) inserting it into the
/// MangledNames string map.
const char *UniqueMangledName(const char *NameStart, const char *NameEnd);
llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref);
llvm::Constant *GetOrCreateLLVMFunction(const char *MangledName,
llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName,
const llvm::Type *Ty,
GlobalDecl D);
llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName,
llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
const llvm::PointerType *PTy,
const VarDecl *D);
@ -492,7 +477,7 @@ private:
void EmitGlobalFunctionDefinition(GlobalDecl GD);
void EmitGlobalVarDefinition(const VarDecl *D);
void EmitAliasDefinition(const ValueDecl *D);
void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
// C++ related functions.
@ -519,9 +504,12 @@ private:
/// a C++ destructor Decl.
void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
/// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals.
/// EmitCXXGlobalInitFunc - Emit the function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
/// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals.
void EmitCXXGlobalDtorFunc();
void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D);
// FIXME: Hardcoding priority here is gross.

View File

@ -469,8 +469,26 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
mangleName(Qualifier->getAsNamespace());
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
mangleType(QualType(Qualifier->getAsType(), 0));
case NestedNameSpecifier::TypeSpecWithTemplate: {
const Type *QTy = Qualifier->getAsType();
if (const TemplateSpecializationType *TST =
dyn_cast<TemplateSpecializationType>(QTy)) {
if (!mangleSubstitution(QualType(TST, 0))) {
TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
assert(TD && "FIXME: Support dependent template names");
mangleTemplatePrefix(TD);
TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
mangleTemplateArgs(*TemplateParameters, TST->getArgs(),
TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
} else {
// We use the QualType mangle type variant here because it handles
// substitutions.
mangleType(QualType(QTy, 0));
}
}
break;
case NestedNameSpecifier::Identifier:
// Member expressions can have these without prefixes.
@ -1144,29 +1162,8 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
void CXXNameMangler::mangleType(const TypenameType *T) {
// Typename types are always nested
Out << 'N';
const Type *QTy = T->getQualifier()->getAsType();
if (const TemplateSpecializationType *TST =
dyn_cast<TemplateSpecializationType>(QTy)) {
if (!mangleSubstitution(QualType(TST, 0))) {
TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
assert(TD && "FIXME: Support dependent template names");
mangleTemplatePrefix(TD);
TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
mangleTemplateArgs(*TemplateParameters, TST->getArgs(),
TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
} else if (const TemplateTypeParmType *TTPT =
dyn_cast<TemplateTypeParmType>(QTy)) {
// We use the QualType mangle type variant here because it handles
// substitutions.
mangleType(QualType(TTPT, 0));
} else
assert(false && "Unhandled type!");
mangleUnresolvedScope(T->getQualifier());
mangleSourceName(T->getIdentifier());
Out << 'E';
}

View File

@ -21,10 +21,8 @@
#include "CGCXX.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h"
namespace llvm {
template<typename T> class SmallVectorImpl;
}
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
namespace clang {
class ASTContext;
@ -37,6 +35,33 @@ namespace clang {
namespace CodeGen {
class CovariantThunkAdjustment;
class ThunkAdjustment;
/// MangleBuffer - a convenient class for storing a name which is
/// either the result of a mangling or is a constant string with
/// external memory ownership.
class MangleBuffer {
public:
void setString(llvm::StringRef Ref) {
String = Ref;
}
llvm::SmallVectorImpl<char> &getBuffer() {
return Buffer;
}
llvm::StringRef getString() const {
if (!String.empty()) return String;
return Buffer.str();
}
operator llvm::StringRef() const {
return getString();
}
private:
llvm::StringRef String;
llvm::SmallString<256> Buffer;
};
/// MangleContext - Context for tracking state which persists across multiple
/// calls to the C++ name mangler.

View File

@ -10,6 +10,7 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang::driver;
@ -155,14 +156,12 @@ SeparateArg::SeparateArg(const Option *Opt, unsigned Index, unsigned _NumValues,
void SeparateArg::render(const ArgList &Args, ArgStringList &Output) const {
if (getOption().hasForceJoinedRender()) {
assert(getNumValues() == 1 && "Cannot force joined render with > 1 args.");
// FIXME: Avoid std::string.
std::string Joined(getOption().getName());
Joined += Args.getArgString(getIndex());
Output.push_back(Args.MakeArgString(Joined.c_str()));
Output.push_back(Args.MakeArgString(llvm::StringRef(getOption().getName()) +
getValue(Args, 0)));
} else {
Output.push_back(Args.getArgString(getIndex()));
for (unsigned i = 0; i < NumValues; ++i)
Output.push_back(Args.getArgString(getIndex() + 1 + i));
Output.push_back(getValue(Args, i));
}
}

View File

@ -61,10 +61,21 @@ void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J,
OS << " \"" << C->getExecutable() << '"';
for (ArgStringList::const_iterator it = C->getArguments().begin(),
ie = C->getArguments().end(); it != ie; ++it) {
if (Quote)
OS << " \"" << *it << '"';
else
OS << ' ' << *it;
OS << ' ';
if (!Quote) {
OS << *it;
continue;
}
// Quote the argument and escape shell special characters; this isn't
// really complete but is good enough.
OS << '"';
for (const char *s = *it; *s; ++s) {
if (*s == '"' || *s == '\\' || *s == '$')
OS << '\\';
OS << *s;
}
OS << '"';
}
OS << Terminator;
} else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
@ -123,8 +134,34 @@ int Compilation::ExecuteCommand(const Command &C,
std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
Argv[C.getArguments().size() + 1] = 0;
if (getDriver().CCCEcho || getArgs().hasArg(options::OPT_v))
PrintJob(llvm::errs(), C, "\n", false);
if (getDriver().CCCEcho || getDriver().CCPrintOptions ||
getArgs().hasArg(options::OPT_v)) {
llvm::raw_ostream *OS = &llvm::errs();
// Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
// output stream.
if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
std::string Error;
OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename,
Error,
llvm::raw_fd_ostream::F_Append);
if (!Error.empty()) {
getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
<< Error;
FailingCommand = &C;
delete OS;
return 1;
}
}
if (getDriver().CCPrintOptions)
*OS << "[Logging clang options]";
PrintJob(*OS, C, "\n", /*Quote=*/getDriver().CCPrintOptions);
if (OS != &llvm::errs())
delete OS;
}
std::string Error;
int Res =

View File

@ -51,10 +51,10 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
DefaultImageName(_DefaultImageName),
DriverTitle("clang \"gcc-compatible\" driver"),
Host(0),
CCCGenericGCCName("gcc"), CCCIsCXX(false), CCCEcho(false),
CCCPrintBindings(false), CheckInputsExist(true), CCCUseClang(true),
CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true),
SuppressMissingInputWarning(false) {
CCCGenericGCCName("gcc"), CCPrintOptionsFilename(0), CCCIsCXX(false),
CCCEcho(false), CCCPrintBindings(false), CCPrintOptions(false),
CheckInputsExist(true), CCCUseClang(true), CCCUseClangCXX(true),
CCCUseClangCPP(true), CCCUsePCH(true), SuppressMissingInputWarning(false) {
if (IsProduction) {
// In a "production" build, only use clang on architectures we expect to
// work, and don't use clang C++.

View File

@ -167,11 +167,13 @@ Option *OptTable::CreateOption(unsigned id) const {
if (info.Flags & RenderAsInput)
Opt->setNoOptAsInput(true);
if (info.Flags & RenderJoined) {
assert(info.Kind == Option::SeparateClass && "Invalid option.");
assert((info.Kind == Option::JoinedOrSeparateClass ||
info.Kind == Option::SeparateClass) && "Invalid option.");
Opt->setForceJoinedRender(true);
}
if (info.Flags & RenderSeparate) {
assert(info.Kind == Option::JoinedClass && "Invalid option.");
assert((info.Kind == Option::JoinedOrSeparateClass ||
info.Kind == Option::JoinedClass) && "Invalid option.");
Opt->setForceSeparateRender(true);
}
if (info.Flags & Unsupported)

View File

@ -394,9 +394,9 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
// this. Perhaps put under -pedantic?
if (getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::thumb)
OSXVersion = 0;
OSXTarget = 0;
else
iPhoneVersion = 0;
iPhoneOSTarget = 0;
}
if (OSXTarget) {

View File

@ -96,6 +96,8 @@ public:
return TargetIsIPhoneOS;
}
bool isTargetInitialized() const { return TargetInitialized; }
void getTargetVersion(unsigned (&Res)[3]) const {
assert(TargetInitialized && "Target not initialized!");
Res[0] = TargetVersion[0];

View File

@ -655,6 +655,12 @@ static std::string getEffectiveClangTriple(const Driver &D,
} else {
const toolchains::Darwin &DarwinTC(
reinterpret_cast<const toolchains::Darwin&>(TC));
// If the target isn't initialized (e.g., an unknown Darwin platform, return
// the default triple).
if (!DarwinTC.isTargetInitialized())
return Triple.getTriple();
unsigned Version[3];
DarwinTC.getTargetVersion(Version);
@ -686,6 +692,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
bool KernelOrKext = Args.hasArg(options::OPT_mkernel,
options::OPT_fapple_kext);
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
@ -870,7 +878,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
options::OPT_fno_asynchronous_unwind_tables,
getToolChain().IsUnwindTablesDefault() &&
!Args.hasArg(options::OPT_mkernel));
!KernelOrKext);
if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
AsynchronousUnwindTables))
CmdArgs.push_back("-munwind-tables");
@ -1029,12 +1037,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
// -fhosted is default.
if (KernelOrKext || Args.hasFlag(options::OPT_ffreestanding,
options::OPT_fhosted,
false))
CmdArgs.push_back("-ffreestanding");
// Forward -f (flag) options which we can pass directly.
Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior);
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_ffreestanding);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions);
// -flax-vector-conversions is default.
if (!Args.hasFlag(options::OPT_flax_vector_conversions,
options::OPT_fno_lax_vector_conversions))
CmdArgs.push_back("-fno-lax-vector-conversions");
Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics);
Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only);
@ -1080,6 +1098,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks");
}
// -fno-access-control is default (for now).
if (Args.hasFlag(options::OPT_faccess_control,
options::OPT_fno_access_control,
false))
CmdArgs.push_back("-faccess-control");
// -fexceptions=0 is default.
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
CmdArgs.push_back("-fexceptions");
@ -1088,7 +1112,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fsjlj-exceptions");
// -frtti is default.
if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
if (KernelOrKext ||
!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-fno-rtti");
// -fsigned-char is default.
@ -1101,6 +1126,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_threadsafe_statics))
CmdArgs.push_back("-fno-threadsafe-statics");
// -fuse-cxa-atexit is default.
if (KernelOrKext || !Args.hasFlag(options::OPT_fuse_cxa_atexit,
options::OPT_fno_use_cxa_atexit))
CmdArgs.push_back("-fno-use-cxa-atexit");
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))

View File

@ -83,7 +83,7 @@ public:
return false;
}
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
}
@ -293,8 +293,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
Clang.getTargetOpts()));
if (!Clang.hasTarget()) {
Clang.takeSourceManager();
Clang.takeFileManager();
Clang.takeDiagnosticClient();
Clang.takeDiagnostics();
return 0;

View File

@ -164,11 +164,12 @@ public:
} // end anonymous namespace
typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap;
typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
namespace {
class PTHWriter {
typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
IDMap IM;
llvm::raw_fd_ostream& Out;
Preprocessor& PP;
@ -272,7 +273,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
// Pad 0's so that we emit tokens to a 4-byte alignment.
// This speed up reading them back in.
Pad(Out, 4);
Offset off = (Offset) Out.tell();
Offset TokenOff = (Offset) Out.tell();
// Keep track of matching '#if' ... '#endif'.
typedef std::vector<std::pair<Offset, unsigned> > PPCondTable;
@ -418,7 +419,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
Emit32(PPCond.size());
for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) {
Emit32(PPCond[i].first - off);
Emit32(PPCond[i].first - TokenOff);
uint32_t x = PPCond[i].second;
assert(x != 0 && "PPCond entry not backpatched.");
// Emit zero for #endifs. This allows us to do checking when
@ -426,7 +427,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
Emit32(x == i ? 0 : x);
}
return PTHEntry(off, PPCondOff);
return PTHEntry(TokenOff, PPCondOff);
}
Offset PTHWriter::EmitCachedSpellings() {
@ -452,7 +453,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) {
// Write the name of the MainFile.
if (!MainFile.empty()) {
EmitString(MainFile);
EmitString(MainFile);
} else {
// String with 0 bytes.
Emit16(0);
@ -549,7 +550,8 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
// Lex through the entire file. This will populate SourceManager with
// all of the header information.
Token Tok;
PP.EnterMainSourceFile();
if (PP.EnterMainSourceFile())
return;
do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
// Generate the PTH file.

View File

@ -107,15 +107,13 @@ void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel,
static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
unsigned argc, char **argv,
llvm::OwningPtr<DiagnosticClient> &DiagClient) {
Diagnostic &Diags) {
std::string ErrorInfo;
llvm::raw_ostream *OS =
new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo);
llvm::OwningPtr<llvm::raw_ostream> OS(
new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo));
if (!ErrorInfo.empty()) {
// FIXME: Do not fail like this.
llvm::errs() << "error opening -dump-build-information file '"
<< DiagOpts.DumpBuildInformation << "', option ignored!\n";
delete OS;
Diags.Report(diag::err_fe_unable_to_open_logfile)
<< DiagOpts.DumpBuildInformation << ErrorInfo;
return;
}
@ -126,8 +124,8 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
// Chain in a diagnostic client which will log the diagnostics.
DiagnosticClient *Logger =
new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true);
DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger));
new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true);
Diags.setClient(new ChainedDiagnosticClient(Diags.getClient(), Logger));
}
void CompilerInstance::createDiagnostics(int Argc, char **Argv) {
@ -165,13 +163,12 @@ Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
if (Opts.VerifyDiagnostics)
DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take()));
Diags->setClient(DiagClient.take());
if (!Opts.DumpBuildInformation.empty())
SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient);
SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
// Configure our handling of diagnostics.
Diags->setClient(DiagClient.take());
if (ProcessWarningOptions(*Diags, Opts))
return 0;
ProcessWarningOptions(*Diags, Opts);
return Diags.take();
}
@ -227,6 +224,9 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
PP->setPTHManager(PTHMgr);
}
if (PPOpts.DetailedRecord)
PP->createPreprocessingRecord();
InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
// Handle generating dependencies, if requested.
@ -429,12 +429,7 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
SourceManager &SourceMgr,
const FrontendOptions &Opts) {
// Figure out where to get and map in the main file.
if (Opts.EmptyInputOnly) {
const char *EmptyStr = "";
llvm::MemoryBuffer *SB =
llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>");
SourceMgr.createMainFileIDForMemBuffer(SB);
} else if (InputFile != "-") {
if (InputFile != "-") {
const FileEntry *File = FileMgr.getFile(InputFile);
if (File) SourceMgr.createMainFileID(File, SourceLocation());
if (SourceMgr.getMainFileID().isInvalid()) {

View File

@ -154,6 +154,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-mcode-model");
Res.push_back(Opts.CodeModel);
}
if (!Opts.CXAAtExit)
Res.push_back("-fno-use-cxa-atexit");
if (Opts.CXXCtorDtorAliases)
Res.push_back("-mconstructor-aliases");
if (!Opts.DebugPass.empty()) {
Res.push_back("-mdebug-pass");
Res.push_back(Opts.DebugPass);
@ -180,8 +184,6 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-mrelocation-model");
Res.push_back(Opts.RelocationModel);
}
if (Opts.CXXCtorDtorAliases)
Res.push_back("-mconstructor-aliases");
if (!Opts.VerifyModule)
Res.push_back("-disable-llvm-verifier");
}
@ -288,6 +290,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::FixIt: return "-fixit";
case frontend::GeneratePCH: return "-emit-pch";
case frontend::GeneratePTH: return "-emit-pth";
case frontend::InitOnly: return "-init-only";
case frontend::ParseNoop: return "-parse-noop";
case frontend::ParsePrintCallbacks: return "-parse-print-callbacks";
case frontend::ParseSyntaxOnly: return "-fsyntax-only";
@ -310,8 +313,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-no-code-completion-debug-printer");
if (Opts.DisableFree)
Res.push_back("-disable-free");
if (Opts.EmptyInputOnly)
Res.push_back("-empty-input-only");
if (Opts.RelocatablePCH)
Res.push_back("-relocatable-pch");
if (Opts.ShowHelp)
@ -575,6 +576,8 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
}
if (!Opts.UsePredefines)
Res.push_back("-undef");
if (Opts.DetailedRecord)
Res.push_back("-detailed-preprocessing-record");
if (!Opts.ImplicitPCHInclude.empty()) {
Res.push_back("-include-pch");
Res.push_back(Opts.ImplicitPCHInclude);
@ -783,6 +786,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.CodeModel = getLastArgValue(Args, OPT_mcode_model);
Opts.DebugPass = getLastArgValue(Args, OPT_mdebug_pass);
Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
@ -793,7 +798,6 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic");
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
@ -876,6 +880,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::GeneratePCH; break;
case OPT_emit_pth:
Opts.ProgramAction = frontend::GeneratePTH; break;
case OPT_init_only:
Opts.ProgramAction = frontend::InitOnly; break;
case OPT_parse_noop:
Opts.ProgramAction = frontend::ParseNoop; break;
case OPT_parse_print_callbacks:
@ -913,7 +919,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.DebugCodeCompletionPrinter =
!Args.hasArg(OPT_no_code_completion_debug_printer);
Opts.DisableFree = Args.hasArg(OPT_disable_free);
Opts.EmptyInputOnly = Args.hasArg(OPT_empty_input_only);
Opts.FixItLocations.clear();
for (arg_iterator it = Args.filtered_begin(OPT_fixit_at),
@ -1232,7 +1237,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
else
Opts.TokenCache = Opts.ImplicitPTHInclude;
Opts.UsePredefines = !Args.hasArg(OPT_undef);
Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
// Add macros from the command line.
for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U),
ie = Args.filtered_end(); it != ie; ++it) {

View File

@ -22,6 +22,18 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Custom Actions
//===----------------------------------------------------------------------===//
ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
return new ASTConsumer();
}
void InitOnlyAction::ExecuteAction() {
}
//===----------------------------------------------------------------------===//
// AST Consumer Actions
//===----------------------------------------------------------------------===//
@ -185,7 +197,8 @@ void DumpTokensAction::ExecuteAction() {
Preprocessor &PP = getCompilerInstance().getPreprocessor();
// Start preprocessing the specified input file.
Token Tok;
PP.EnterMainSourceFile();
if (PP.EnterMainSourceFile())
return;
do {
PP.Lex(Tok);
PP.DumpToken(Tok, true);
@ -213,7 +226,8 @@ void ParseOnlyAction::ExecuteAction() {
llvm::OwningPtr<Action> PA(new MinimalAction(PP));
Parser P(PP, *PA);
PP.EnterMainSourceFile();
if (PP.EnterMainSourceFile())
return;
P.ParseTranslationUnit();
}
@ -222,7 +236,8 @@ void PreprocessOnlyAction::ExecuteAction() {
Token Tok;
// Start parsing the specified input file.
PP.EnterMainSourceFile();
if (PP.EnterMainSourceFile())
return;
do {
PP.Lex(Tok);
} while (Tok.isNot(tok::eof));
@ -237,7 +252,8 @@ void PrintParseAction::ExecuteAction() {
llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));
Parser P(PP, *PA);
PP.EnterMainSourceFile();
if (PP.EnterMainSourceFile())
return;
P.ParseTranslationUnit();
}

View File

@ -21,6 +21,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/OnDiskHashTable.h"
@ -150,7 +151,10 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
std::pair<llvm::StringRef,llvm::StringRef> Split =
llvm::StringRef(PP.getPredefines()).split(PCHInclude.str());
llvm::StringRef Left = Split.first, Right = Split.second;
assert(Left != PP.getPredefines() && "Missing PCH include entry!");
if (Left == PP.getPredefines()) {
Error("Missing PCH include entry!");
return true;
}
// If the predefines is equal to the joined left and right halves, we're done!
if (Left.size() + Right.size() == PCHPredef.size() &&
@ -300,8 +304,10 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
return false;
}
void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI,
unsigned ID) {
PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID);
++NumHeaderInfos;
}
void PCHValidator::ReadCounter(unsigned Value) {
@ -321,8 +327,9 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
IdentifierOffsets(0),
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
NumStatHits(0), NumStatMisses(0),
TotalNumSelectors(0), MacroDefinitionOffsets(0),
NumPreallocatedPreprocessingEntities(0),
isysroot(isysroot), NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), NumStatementsRead(0),
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
@ -338,8 +345,9 @@ PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
IdentifierOffsets(0),
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
NumStatHits(0), NumStatMisses(0),
TotalNumSelectors(0), MacroDefinitionOffsets(0),
NumPreallocatedPreprocessingEntities(0),
isysroot(isysroot), NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), NumStatementsRead(0),
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
@ -601,10 +609,8 @@ public:
typedef OnDiskChainedHashTable<PCHIdentifierLookupTrait>
PCHIdentifierLookupTable;
bool PCHReader::Error(const char *Msg) {
unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Fatal, Msg);
Diag(DiagID);
return true;
void PCHReader::Error(const char *Msg) {
Diag(diag::err_fe_pch_malformed) << Msg;
}
/// \brief Check the contents of the predefines buffer against the
@ -850,17 +856,6 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
return Failure;
break;
case pch::SM_HEADER_FILE_INFO: {
HeaderFileInfo HFI;
HFI.isImport = Record[0];
HFI.DirInfo = Record[1];
HFI.NumIncludes = Record[2];
HFI.ControllingMacroID = Record[3];
if (Listener)
Listener->ReadHeaderFileInfo(HFI);
break;
}
case pch::SM_SLOC_FILE_ENTRY:
case pch::SM_SLOC_BUFFER_ENTRY:
case pch::SM_SLOC_INSTANTIATION_ENTRY:
@ -910,6 +905,11 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
return Failure;
}
if (Record.size() < 8) {
Error("source location entry is incorrect");
return Failure;
}
FileID FID = SourceMgr.createFileID(File,
SourceLocation::getFromRawEncoding(Record[1]),
(SrcMgr::CharacteristicKind)Record[2],
@ -918,6 +918,14 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile())
.setHasLineDirectives();
// Reconstruct header-search information for this file.
HeaderFileInfo HFI;
HFI.isImport = Record[4];
HFI.DirInfo = Record[5];
HFI.NumIncludes = Record[6];
HFI.ControllingMacroID = Record[7];
if (Listener)
Listener->ReadHeaderFileInfo(HFI, File->getUID());
break;
}
@ -928,8 +936,12 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
Record.clear();
unsigned RecCode
= SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file");
(void)RecCode;
if (RecCode != pch::SM_SLOC_BUFFER_BLOB) {
Error("PCH record has invalid code");
return Failure;
}
llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBuffer(BlobStart,
BlobStart + BlobLen - 1,
@ -1038,12 +1050,14 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
MacroInfo *MI = PP->AllocateMacroInfo(Loc);
MI->setIsUsed(isUsed);
unsigned NextIndex = 3;
if (RecType == pch::PP_MACRO_FUNCTION_LIKE) {
// Decode function-like macro info.
bool isC99VarArgs = Record[3];
bool isGNUVarArgs = Record[4];
MacroArgs.clear();
unsigned NumArgs = Record[5];
NextIndex = 6 + NumArgs;
for (unsigned i = 0; i != NumArgs; ++i)
MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i]));
@ -1061,6 +1075,13 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
// Remember that we saw this macro last so that we add the tokens that
// form its body to it.
Macro = MI;
if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) {
// We have a macro definition. Load it now.
PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro,
getMacroDefinition(Record[NextIndex]));
}
++NumMacrosRead;
break;
}
@ -1081,6 +1102,64 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
Macro->AddTokenToBody(Tok);
break;
}
case pch::PP_MACRO_INSTANTIATION: {
// If we already have a macro, that means that we've hit the end
// of the definition of the macro we were looking for. We're
// done.
if (Macro)
return;
if (!PP->getPreprocessingRecord()) {
Error("missing preprocessing record in PCH file");
return;
}
PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
if (PPRec.getPreprocessedEntity(Record[0]))
return;
MacroInstantiation *MI
= new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]),
SourceRange(
SourceLocation::getFromRawEncoding(Record[1]),
SourceLocation::getFromRawEncoding(Record[2])),
getMacroDefinition(Record[4]));
PPRec.SetPreallocatedEntity(Record[0], MI);
return;
}
case pch::PP_MACRO_DEFINITION: {
// If we already have a macro, that means that we've hit the end
// of the definition of the macro we were looking for. We're
// done.
if (Macro)
return;
if (!PP->getPreprocessingRecord()) {
Error("missing preprocessing record in PCH file");
return;
}
PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
if (PPRec.getPreprocessedEntity(Record[0]))
return;
if (Record[1] >= MacroDefinitionsLoaded.size()) {
Error("out-of-bounds macro definition record");
return;
}
MacroDefinition *MD
= new (PPRec) MacroDefinition(DecodeIdentifierInfo(Record[4]),
SourceLocation::getFromRawEncoding(Record[5]),
SourceRange(
SourceLocation::getFromRawEncoding(Record[2]),
SourceLocation::getFromRawEncoding(Record[3])));
PPRec.SetPreallocatedEntity(Record[0], MD);
MacroDefinitionsLoaded[Record[1]] = MD;
return;
}
}
}
}
@ -1130,16 +1209,32 @@ void PCHReader::ReadDefinedMacros() {
case pch::PP_MACRO_OBJECT_LIKE:
case pch::PP_MACRO_FUNCTION_LIKE:
DecodeIdentifierInfo(Record[0]);
DecodeIdentifierInfo(Record[0]);
break;
case pch::PP_TOKEN:
// Ignore tokens.
break;
case pch::PP_MACRO_INSTANTIATION:
case pch::PP_MACRO_DEFINITION:
// Read the macro record.
ReadMacroRecord(Cursor.GetCurrentBitNo());
break;
}
}
}
MacroDefinition *PCHReader::getMacroDefinition(pch::IdentID ID) {
if (ID == 0 || ID >= MacroDefinitionsLoaded.size())
return 0;
if (!MacroDefinitionsLoaded[ID])
ReadMacroRecord(MacroDefinitionOffsets[ID]);
return MacroDefinitionsLoaded[ID];
}
/// \brief If we are loading a relocatable PCH file, and the filename is
/// not an absolute path, add the system root to the beginning of the file
/// name.
@ -1408,11 +1503,6 @@ PCHReader::ReadPCHBlock() {
MaybeAddSystemRootToFilename(OriginalFileName);
break;
case pch::COMMENT_RANGES:
Comments = (SourceRange *)BlobStart;
NumComments = BlobLen / sizeof(SourceRange);
break;
case pch::VERSION_CONTROL_BRANCH_REVISION: {
const std::string &CurBranch = getClangFullRepositoryVersion();
llvm::StringRef PCHBranch(BlobStart, BlobLen);
@ -1422,6 +1512,19 @@ PCHReader::ReadPCHBlock() {
}
break;
}
case pch::MACRO_DEFINITION_OFFSETS:
MacroDefinitionOffsets = (const uint32_t *)BlobStart;
if (PP) {
if (!PP->getPreprocessingRecord())
PP->createPreprocessingRecord();
PP->getPreprocessingRecord()->SetExternalSource(*this, Record[0]);
} else {
NumPreallocatedPreprocessingEntities = Record[0];
}
MacroDefinitionsLoaded.resize(Record[1]);
break;
}
}
Error("premature end of bitstream in PCH file");
@ -1553,6 +1656,18 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
return Success;
}
void PCHReader::setPreprocessor(Preprocessor &pp) {
PP = &pp;
if (NumPreallocatedPreprocessingEntities) {
if (!PP->getPreprocessingRecord())
PP->createPreprocessingRecord();
PP->getPreprocessingRecord()->SetExternalSource(*this,
NumPreallocatedPreprocessingEntities);
NumPreallocatedPreprocessingEntities = 0;
}
}
void PCHReader::InitializeContext(ASTContext &Ctx) {
Context = &Ctx;
assert(Context && "Passed null context!");
@ -1584,29 +1699,44 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
Context->setObjCFastEnumerationStateType(GetType(FastEnum));
if (unsigned File = SpecialTypes[pch::SPECIAL_TYPE_FILE]) {
QualType FileType = GetType(File);
assert(!FileType.isNull() && "FILE type is NULL");
if (FileType.isNull()) {
Error("FILE type is NULL");
return;
}
if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
Context->setFILEDecl(Typedef->getDecl());
else {
const TagType *Tag = FileType->getAs<TagType>();
assert(Tag && "Invalid FILE type in PCH file");
if (!Tag) {
Error("Invalid FILE type in PCH file");
return;
}
Context->setFILEDecl(Tag->getDecl());
}
}
if (unsigned Jmp_buf = SpecialTypes[pch::SPECIAL_TYPE_jmp_buf]) {
QualType Jmp_bufType = GetType(Jmp_buf);
assert(!Jmp_bufType.isNull() && "jmp_bug type is NULL");
if (Jmp_bufType.isNull()) {
Error("jmp_bug type is NULL");
return;
}
if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
Context->setjmp_bufDecl(Typedef->getDecl());
else {
const TagType *Tag = Jmp_bufType->getAs<TagType>();
assert(Tag && "Invalid jmp_bug type in PCH file");
if (!Tag) {
Error("Invalid jmp_bug type in PCH file");
return;
}
Context->setjmp_bufDecl(Tag->getDecl());
}
}
if (unsigned Sigjmp_buf = SpecialTypes[pch::SPECIAL_TYPE_sigjmp_buf]) {
QualType Sigjmp_bufType = GetType(Sigjmp_buf);
assert(!Sigjmp_bufType.isNull() && "sigjmp_buf type is NULL");
if (Sigjmp_bufType.isNull()) {
Error("sigjmp_buf type is NULL");
return;
}
if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
Context->setsigjmp_bufDecl(Typedef->getDecl());
else {
@ -1799,10 +1929,8 @@ bool PCHReader::ParseLanguageOptions(
return false;
}
void PCHReader::ReadComments(std::vector<SourceRange> &Comments) {
Comments.resize(NumComments);
std::copy(this->Comments, this->Comments + NumComments,
Comments.begin());
void PCHReader::ReadPreprocessedEntities() {
ReadDefinedMacros();
}
/// \brief Read and return the type at the given offset.
@ -1823,45 +1951,65 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
unsigned Code = DeclsCursor.ReadCode();
switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) {
case pch::TYPE_EXT_QUAL: {
assert(Record.size() == 2 &&
"Incorrect encoding of extended qualifier type");
if (Record.size() != 2) {
Error("Incorrect encoding of extended qualifier type");
return QualType();
}
QualType Base = GetType(Record[0]);
Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]);
return Context->getQualifiedType(Base, Quals);
}
case pch::TYPE_COMPLEX: {
assert(Record.size() == 1 && "Incorrect encoding of complex type");
if (Record.size() != 1) {
Error("Incorrect encoding of complex type");
return QualType();
}
QualType ElemType = GetType(Record[0]);
return Context->getComplexType(ElemType);
}
case pch::TYPE_POINTER: {
assert(Record.size() == 1 && "Incorrect encoding of pointer type");
if (Record.size() != 1) {
Error("Incorrect encoding of pointer type");
return QualType();
}
QualType PointeeType = GetType(Record[0]);
return Context->getPointerType(PointeeType);
}
case pch::TYPE_BLOCK_POINTER: {
assert(Record.size() == 1 && "Incorrect encoding of block pointer type");
if (Record.size() != 1) {
Error("Incorrect encoding of block pointer type");
return QualType();
}
QualType PointeeType = GetType(Record[0]);
return Context->getBlockPointerType(PointeeType);
}
case pch::TYPE_LVALUE_REFERENCE: {
assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type");
if (Record.size() != 1) {
Error("Incorrect encoding of lvalue reference type");
return QualType();
}
QualType PointeeType = GetType(Record[0]);
return Context->getLValueReferenceType(PointeeType);
}
case pch::TYPE_RVALUE_REFERENCE: {
assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type");
if (Record.size() != 1) {
Error("Incorrect encoding of rvalue reference type");
return QualType();
}
QualType PointeeType = GetType(Record[0]);
return Context->getRValueReferenceType(PointeeType);
}
case pch::TYPE_MEMBER_POINTER: {
assert(Record.size() == 1 && "Incorrect encoding of member pointer type");
if (Record.size() != 1) {
Error("Incorrect encoding of member pointer type");
return QualType();
}
QualType PointeeType = GetType(Record[0]);
QualType ClassType = GetType(Record[1]);
return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr());
@ -1957,7 +2105,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0])));
case pch::TYPE_TYPEDEF:
assert(Record.size() == 1 && "incorrect encoding of typedef type");
if (Record.size() != 1) {
Error("incorrect encoding of typedef type");
return QualType();
}
return Context->getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0])));
case pch::TYPE_TYPEOF_EXPR:
@ -1976,15 +2127,24 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
return Context->getDecltypeType(ReadTypeExpr());
case pch::TYPE_RECORD:
assert(Record.size() == 1 && "incorrect encoding of record type");
if (Record.size() != 1) {
Error("incorrect encoding of record type");
return QualType();
}
return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0])));
case pch::TYPE_ENUM:
assert(Record.size() == 1 && "incorrect encoding of enum type");
if (Record.size() != 1) {
Error("incorrect encoding of enum type");
return QualType();
}
return Context->getTypeDeclType(cast<EnumDecl>(GetDecl(Record[0])));
case pch::TYPE_ELABORATED: {
assert(Record.size() == 2 && "incorrect encoding of elaborated type");
if (Record.size() != 2) {
Error("incorrect encoding of elaborated type");
return QualType();
}
unsigned Tag = Record[1];
return Context->getElaboratedType(GetType(Record[0]),
(ElaboratedType::TagKind) Tag);
@ -2329,8 +2489,12 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
llvm::SmallVectorImpl<pch::DeclID> &Decls) {
assert(DC->hasExternalLexicalStorage() &&
"DeclContext has no lexical decls in storage");
uint64_t Offset = DeclContextOffsets[DC].first;
assert(Offset && "DeclContext has no lexical decls in storage");
if (Offset == 0) {
Error("DeclContext has no lexical decls in storage");
return true;
}
// Keep track of where we are in the stream, then jump back there
// after reading this context.
@ -2342,8 +2506,10 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
(void)RecCode;
assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block");
if (RecCode != pch::DECL_CONTEXT_LEXICAL) {
Error("Expected lexical block");
return true;
}
// Load all of the declaration IDs
Decls.clear();
@ -2357,7 +2523,10 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
assert(DC->hasExternalVisibleStorage() &&
"DeclContext has no visible decls in storage");
uint64_t Offset = DeclContextOffsets[DC].second;
assert(Offset && "DeclContext has no visible decls in storage");
if (Offset == 0) {
Error("DeclContext has no visible decls in storage");
return true;
}
// Keep track of where we are in the stream, then jump back there
// after reading this context.
@ -2369,8 +2538,11 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
(void)RecCode;
assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block");
if (RecCode != pch::DECL_CONTEXT_VISIBLE) {
Error("Expected visible block");
return true;
}
if (Record.size() == 0)
return false;

View File

@ -21,6 +21,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h"
@ -563,9 +564,10 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SOURCE_LOCATION_PRELOADS);
RECORD(STAT_CACHE);
RECORD(EXT_VECTOR_DECLS);
RECORD(COMMENT_RANGES);
RECORD(VERSION_CONTROL_BRANCH_REVISION);
RECORD(UNUSED_STATIC_FUNCS);
RECORD(MACRO_DEFINITION_OFFSETS);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY);
@ -573,14 +575,15 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SM_SLOC_BUFFER_BLOB);
RECORD(SM_SLOC_INSTANTIATION_ENTRY);
RECORD(SM_LINE_TABLE);
RECORD(SM_HEADER_FILE_INFO);
// Preprocessor Block.
BLOCK(PREPROCESSOR_BLOCK);
RECORD(PP_MACRO_OBJECT_LIKE);
RECORD(PP_MACRO_FUNCTION_LIKE);
RECORD(PP_TOKEN);
RECORD(PP_MACRO_INSTANTIATION);
RECORD(PP_MACRO_DEFINITION);
// Decls and Types block.
BLOCK(DECLTYPES_BLOCK);
RECORD(TYPE_EXT_QUAL);
@ -918,6 +921,11 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
// HeaderFileInfo fields.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isImport
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // DirInfo
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumIncludes
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // ControllingMacro
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
return Stream.EmitAbbrev(Abbrev);
}
@ -1019,20 +1027,6 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Stream.EmitRecord(pch::SM_LINE_TABLE, Record);
}
// Write out entries for all of the header files we know about.
HeaderSearch &HS = PP.getHeaderSearchInfo();
Record.clear();
for (HeaderSearch::header_file_iterator I = HS.header_file_begin(),
E = HS.header_file_end();
I != E; ++I) {
Record.push_back(I->isImport);
Record.push_back(I->DirInfo);
Record.push_back(I->NumIncludes);
AddIdentifierRef(I->ControllingMacro, Record);
Stream.EmitRecord(pch::SM_HEADER_FILE_INFO, Record);
Record.clear();
}
// Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets;
@ -1069,6 +1063,16 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// The source location entry is a file. The blob associated
// with this entry is the file name.
// Emit header-search information associated with this file.
HeaderFileInfo HFI;
HeaderSearch &HS = PP.getHeaderSearchInfo();
if (Content->Entry->getUID() < HS.header_file_size())
HFI = HS.header_file_begin()[Content->Entry->getUID()];
Record.push_back(HFI.isImport);
Record.push_back(HFI.DirInfo);
Record.push_back(HFI.NumIncludes);
AddIdentifierRef(HFI.ControllingMacro, Record);
// Turn the file name into an absolute path, if it isn't already.
const char *Filename = Content->Entry->getName();
llvm::sys::Path FilePath(Filename, strlen(Filename));
@ -1174,6 +1178,7 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
// Loop over all the macro definitions that are live at the end of the file,
// emitting each to the PP section.
PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
I != E; ++I) {
// FIXME: This emits macros in hash table order, we should do it in a stable
@ -1203,6 +1208,12 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
I != E; ++I)
AddIdentifierRef(*I, Record);
}
// If we have a detailed preprocessing record, record the macro definition
// ID that corresponds to this macro.
if (PPRec)
Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI)));
Stream.EmitRecord(Code, Record);
Record.clear();
@ -1230,25 +1241,68 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
}
++NumMacros;
}
// If the preprocessor has a preprocessing record, emit it.
unsigned NumPreprocessingRecords = 0;
if (PPRec) {
for (PreprocessingRecord::iterator E = PPRec->begin(), EEnd = PPRec->end();
E != EEnd; ++E) {
Record.clear();
if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
Record.push_back(NumPreprocessingRecords++);
AddSourceLocation(MI->getSourceRange().getBegin(), Record);
AddSourceLocation(MI->getSourceRange().getEnd(), Record);
AddIdentifierRef(MI->getName(), Record);
Record.push_back(getMacroDefinitionID(MI->getDefinition()));
Stream.EmitRecord(pch::PP_MACRO_INSTANTIATION, Record);
continue;
}
if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
// Record this macro definition's location.
pch::IdentID ID = getMacroDefinitionID(MD);
if (ID != MacroDefinitionOffsets.size()) {
if (ID > MacroDefinitionOffsets.size())
MacroDefinitionOffsets.resize(ID + 1);
MacroDefinitionOffsets[ID] = Stream.GetCurrentBitNo();
} else
MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo());
Record.push_back(NumPreprocessingRecords++);
Record.push_back(ID);
AddSourceLocation(MD->getSourceRange().getBegin(), Record);
AddSourceLocation(MD->getSourceRange().getEnd(), Record);
AddIdentifierRef(MD->getName(), Record);
AddSourceLocation(MD->getLocation(), Record);
Stream.EmitRecord(pch::PP_MACRO_DEFINITION, Record);
continue;
}
}
}
Stream.ExitBlock();
}
void PCHWriter::WriteComments(ASTContext &Context) {
using namespace llvm;
if (Context.Comments.empty())
return;
BitCodeAbbrev *CommentAbbrev = new BitCodeAbbrev();
CommentAbbrev->Add(BitCodeAbbrevOp(pch::COMMENT_RANGES));
CommentAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned CommentCode = Stream.EmitAbbrev(CommentAbbrev);
RecordData Record;
Record.push_back(pch::COMMENT_RANGES);
Stream.EmitRecordWithBlob(CommentCode, Record,
(const char*)&Context.Comments[0],
Context.Comments.size() * sizeof(SourceRange));
// Write the offsets table for the preprocessing record.
if (NumPreprocessingRecords > 0) {
// Write the offsets table for identifier IDs.
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(pch::MACRO_DEFINITION_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
Record.clear();
Record.push_back(pch::MACRO_DEFINITION_OFFSETS);
Record.push_back(NumPreprocessingRecords);
Record.push_back(MacroDefinitionOffsets.size());
Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record,
(const char *)&MacroDefinitionOffsets.front(),
MacroDefinitionOffsets.size() * sizeof(uint32_t));
}
}
//===----------------------------------------------------------------------===//
@ -2009,13 +2063,12 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Write the remaining PCH contents.
RecordData Record;
Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5);
WriteMetadata(Context, isysroot);
WriteLanguageOptions(Context.getLangOptions());
if (StatCalls && !isysroot)
WriteStatCache(*StatCalls, isysroot);
WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
WriteComments(Context);
// Write the record of special types.
Record.clear();
@ -2149,6 +2202,16 @@ pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID;
}
pch::IdentID PCHWriter::getMacroDefinitionID(MacroDefinition *MD) {
if (MD == 0)
return 0;
pch::IdentID &ID = MacroDefinitions[MD];
if (ID == 0)
ID = MacroDefinitions.size();
return ID;
}
void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
if (SelRef.getAsOpaquePtr() == 0) {
Record.push_back(0);

View File

@ -448,7 +448,8 @@ static int MacroIDCompare(const void* a, const void* b) {
static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
// -dM mode just scans and ignores all tokens in the files, then dumps out
// the macro table at the end.
PP.EnterMainSourceFile();
if (PP.EnterMainSourceFile())
return;
Token Tok;
do PP.Lex(Tok);
@ -495,7 +496,8 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
PP.addPPCallbacks(Callbacks);
// After we have configured the preprocessor, enter the main file.
PP.EnterMainSourceFile();
if (PP.EnterMainSourceFile())
return;
// Consume all of the tokens that come from the predefines buffer. Those
// should not be emitted into the output and are guaranteed to be at the

View File

@ -101,7 +101,8 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
// Get the first preprocessing token.
PP.EnterMainSourceFile();
if (PP.EnterMainSourceFile())
return;
Token PPTok;
PP.Lex(PPTok);

View File

@ -31,7 +31,7 @@
#include <algorithm>
using namespace clang;
bool clang::ProcessWarningOptions(Diagnostic &Diags,
void clang::ProcessWarningOptions(Diagnostic &Diags,
const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
@ -122,6 +122,4 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt);
}
return false;
}

View File

@ -33,7 +33,6 @@
typedef double __m128d __attribute__((__vector_size__(16)));
typedef long long __m128i __attribute__((__vector_size__(16)));
typedef int __v4si __attribute__((__vector_size__(16)));
typedef short __v8hi __attribute__((__vector_size__(16)));
typedef char __v16qi __attribute__((__vector_size__(16)));

35
lib/Headers/nmmintrin.h Normal file
View File

@ -0,0 +1,35 @@
/*===---- nmmintrin.h - SSE intrinsics -------------------------------------===
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*===-----------------------------------------------------------------------===
*/
#ifndef _NMMINTRIN_H
#define _NMMINTRIN_H
#ifndef __SSE4_2__
#error "SSE4.2 instruction set not enabled"
#else
/* To match expectations of gcc we put the sse4.2 definitions into smmintrin.h,
just include it now then. */
#include <smmintrin.h>
#endif /* __SSE4_2__ */
#endif /* _NMMINTRIN_H */

View File

@ -337,6 +337,118 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
/* SSE4 Multiple Packed Sums of Absolute Difference. */
#define _mm_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw128((X), (Y), (M))
/* These definitions are normally in nmmintrin.h, but gcc puts them in here
so we'll do the same. */
#ifdef __SSE4_2__
/* These specify the type of data that we're comparing. */
#define _SIDD_UBYTE_OPS 0x00
#define _SIDD_UWORD_OPS 0x01
#define _SIDD_SBYTE_OPS 0x02
#define _SIDD_SWORD_OPS 0x03
/* These specify the type of comparison operation. */
#define _SIDD_CMP_EQUAL_ANY 0x00
#define _SIDD_CMP_RANGES 0x04
#define _SIDD_CMP_EQUAL_EACH 0x08
#define _SIDD_CMP_EQUAL_ORDERED 0x0c
/* These macros specify the polarity of the operation. */
#define _SIDD_POSITIVE_POLARITY 0x00
#define _SIDD_NEGATIVE_POLARITY 0x10
#define _SIDD_MASKED_POSITIVE_POLARITY 0x20
#define _SIDD_MASKED_NEGATIVE_POLARITY 0x30
/* These macros are used in _mm_cmpXstri() to specify the return. */
#define _SIDD_LEAST_SIGNIFICANT 0x00
#define _SIDD_MOST_SIGNIFICANT 0x40
/* These macros are used in _mm_cmpXstri() to specify the return. */
#define _SIDD_BIT_MASK 0x00
#define _SIDD_UNIT_MASK 0x40
/* SSE4.2 Packed Comparison Intrinsics. */
#define _mm_cmpistrm(A, B, M) __builtin_ia32_pcmpistrm128((A), (B), (M))
#define _mm_cmpistri(A, B, M) __builtin_ia32_pcmpistri128((A), (B), (M))
#define _mm_cmpestrm(A, LA, B, LB, M) \
__builtin_ia32_pcmpestrm128((A), (LA), (B), (LB), (M))
#define _mm_cmpestri(X, LX, Y, LY, M) \
__builtin_ia32_pcmpestri128((A), (LA), (B), (LB), (M))
/* SSE4.2 Packed Comparison Intrinsics and EFlag Reading. */
#define _mm_cmpistra(A, LA, B, LB, M) \
__builtin_ia32_pcmpistria128((A), (LA), (B), (LB), (M))
#define _mm_cmpistrc(A, LA, B, LB, M) \
__builtin_ia32_pcmpistric128((A), (LA), (B), (LB), (M))
#define _mm_cmpistro(A, LA, B, LB, M) \
__builtin_ia32_pcmpistrio128((A), (LA), (B), (LB), (M))
#define _mm_cmpistrs(A, LA, B, LB, M) \
__builtin_ia32_pcmpistris128((A), (LA), (B), (LB), (M))
#define _mm_cmpistrz(A, LA, B, LB, M) \
__builtin_ia32_pcmpistriz128((A), (LA), (B), (LB), (M))
#define _mm_cmpestra(A, LA, B, LB, M) \
__builtin_ia32_pcmpestria128((A), (LA), (B), (LB), (M))
#define _mm_cmpestrc(A, LA, B, LB, M) \
__builtin_ia32_pcmpestric128((A), (LA), (B), (LB), (M))
#define _mm_cmpestro(A, LA, B, LB, M) \
__builtin_ia32_pcmpestrio128((A), (LA), (B), (LB), (M))
#define _mm_cmpestrs(A, LA, B, LB, M) \
__builtin_ia32_pcmpestris128((A), (LA), (B), (LB), (M))
#define _mm_cmpestrz(A, LA, B, LB, M) \
__builtin_ia32_pcmpestriz128((A), (LA), (B), (LB), (M))
/* SSE4.2 Compare Packed Data -- Greater Than. */
static inline __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_epi64(__m128i __V1, __m128i __V2)
{
return __builtin_ia32_pcmpgtq((__v2di)__V1, (__v2di)__V2);
}
/* SSE4.2 Accumulate CRC32. */
static inline unsigned int __attribute__((__always_inline__, __nodebug__))
_mm_crc32_u8(unsigned int __C, unsigned char __D)
{
return __builtin_ia32_crc32qi(__C, __D);
}
static inline unsigned int __attribute__((__always_inline__, __nodebug__))
_mm_crc32_u16(unsigned int __C, unsigned short __D)
{
return __builtin_ia32_crc32hi(__C, __D);
}
static inline unsigned int __attribute__((__always_inline__, __nodebug__))
_mm_crc32_u32(unsigned int __C, unsigned int __D)
{
return __builtin_ia32_crc32si(__C, __D);
}
#ifdef __x86_64__
static inline unsigned long long __attribute__((__always_inline__, __nodebug__))
_mm_crc32_u64(unsigned long long __C, unsigned long long __D)
{
return __builtin_ia32_crc32di(__C, __D);
}
#endif /* __x86_64__ */
/* SSE4.2 Population Count. */
static inline int __attribute__((__always_inline__, __nodebug__))
_mm_popcnt_u32(unsigned int __A)
{
return __builtin_popcount(__A);
}
#ifdef __x86_64__
static inline long long __attribute__((__always_inline__, __nodebug__))
_mm_popcnt_u64(unsigned long long __A)
{
return __builtin_popcountll(__A);
}
#endif /* __x86_64__ */
#endif /* __SSE4_2__ */
#endif /* __SSE4_1__ */
#endif /* _SMMINTRIN_H */

26
lib/Headers/varargs.h Normal file
View File

@ -0,0 +1,26 @@
/*===---- varargs.h - Variable argument handling -------------------------------------===
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*===-----------------------------------------------------------------------===
*/
#ifndef __VARARGS_H
#define __VARARGS_H
#error "Please use <stdarg.h> instead of <varargs.h>"
#endif

View File

@ -30,6 +30,7 @@
#include <mmintrin.h>
typedef int __v4si __attribute__((__vector_size__(16)));
typedef float __v4sf __attribute__((__vector_size__(16)));
typedef float __m128 __attribute__((__vector_size__(16)));
@ -150,28 +151,24 @@ _mm_max_ps(__m128 a, __m128 b)
static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_and_ps(__m128 a, __m128 b)
{
typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)((__v4si)a & (__v4si)b);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_andnot_ps(__m128 a, __m128 b)
{
typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)(~(__v4si)a & (__v4si)b);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_or_ps(__m128 a, __m128 b)
{
typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)((__v4si)a | (__v4si)b);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_xor_ps(__m128 a, __m128 b)
{
typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)((__v4si)a ^ (__v4si)b);
}

View File

@ -16,6 +16,7 @@ add_clang_library(clangLex
PPMacroExpansion.cpp
PTHLexer.cpp
Pragma.cpp
PreprocessingRecord.cpp
Preprocessor.cpp
PreprocessorLexer.cpp
ScratchBuffer.cpp

View File

@ -1036,7 +1036,11 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
// If this BCPL-style comment is in a macro definition, transmogrify it into
// a C-style block comment.
std::string Spelling = PP->getSpelling(Result);
bool Invalid = false;
std::string Spelling = PP->getSpelling(Result, &Invalid);
if (Invalid)
return true;
assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?");
Spelling[1] = '*'; // Change prefix to "/*".
Spelling += "*/"; // add suffix.

View File

@ -208,24 +208,31 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
if (Tok.is(tok::string_literal) || // "foo"
Tok.is(tok::wide_string_literal) || // L"foo"
Tok.is(tok::char_constant)) { // 'x' and L'x'.
std::string Str = Lexer::Stringify(PP.getSpelling(Tok));
Result.append(Str.begin(), Str.end());
bool Invalid = false;
std::string TokStr = PP.getSpelling(Tok, &Invalid);
if (!Invalid) {
std::string Str = Lexer::Stringify(TokStr);
Result.append(Str.begin(), Str.end());
}
} else {
// Otherwise, just append the token. Do some gymnastics to get the token
// in place and avoid copies where possible.
unsigned CurStrLen = Result.size();
Result.resize(CurStrLen+Tok.getLength());
const char *BufPtr = &Result[CurStrLen];
unsigned ActualTokLen = PP.getSpelling(Tok, BufPtr);
bool Invalid = false;
unsigned ActualTokLen = PP.getSpelling(Tok, BufPtr, &Invalid);
// If getSpelling returned a pointer to an already uniqued version of the
// string instead of filling in BufPtr, memcpy it onto our string.
if (BufPtr != &Result[CurStrLen])
memcpy(&Result[CurStrLen], BufPtr, ActualTokLen);
if (!Invalid) {
// If getSpelling returned a pointer to an already uniqued version of
// the string instead of filling in BufPtr, memcpy it onto our string.
if (BufPtr != &Result[CurStrLen])
memcpy(&Result[CurStrLen], BufPtr, ActualTokLen);
// If the token was dirty, the spelling may be shorter than the token.
if (ActualTokLen != Tok.getLength())
Result.resize(CurStrLen+ActualTokLen);
// If the token was dirty, the spelling may be shorter than the token.
if (ActualTokLen != Tok.getLength())
Result.resize(CurStrLen+ActualTokLen);
}
}
}

View File

@ -71,7 +71,11 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
if (II == 0) {
std::string Spelling = getSpelling(MacroNameTok);
bool Invalid = false;
std::string Spelling = getSpelling(MacroNameTok, &Invalid);
if (Invalid)
return;
const IdentifierInfo &Info = Identifiers.get(Spelling);
if (Info.isCPlusPlusOperatorKeyword())
// C++ 2.5p2: Alternative tokens behave the same as its primary token
@ -204,7 +208,12 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// to spell an i/e in a strange way that is another letter. Skipping this
// allows us to avoid looking up the identifier info for #define/#undef and
// other common directives.
const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation());
bool Invalid = false;
const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation(),
&Invalid);
if (Invalid)
return;
char FirstChar = RawCharData[0];
if (FirstChar >= 'a' && FirstChar <= 'z' &&
FirstChar != 'i' && FirstChar != 'e') {
@ -614,8 +623,11 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
llvm::SmallString<64> IntegerBuffer;
IntegerBuffer.resize(DigitTok.getLength());
const char *DigitTokBegin = &IntegerBuffer[0];
unsigned ActualLength = PP.getSpelling(DigitTok, DigitTokBegin);
bool Invalid = false;
unsigned ActualLength = PP.getSpelling(DigitTok, DigitTokBegin, &Invalid);
if (Invalid)
return true;
// Verify that we have a simple digit-sequence, and compute the value. This
// is always a simple digit string computed in decimal, so we do this manually
// here.
@ -900,8 +912,12 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
// Verify that there is nothing after the string, other than EOM.
CheckEndOfDirective("ident");
if (Callbacks)
Callbacks->Ident(Tok.getLocation(), getSpelling(StrTok));
if (Callbacks) {
bool Invalid = false;
std::string Str = getSpelling(StrTok, &Invalid);
if (!Invalid)
Callbacks->Ident(Tok.getLocation(), Str);
}
}
//===----------------------------------------------------------------------===//

View File

@ -80,8 +80,10 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
}
// Get the MemoryBuffer for this FID, if it fails, we fail.
const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID);
if (!InputFile)
bool Invalid = false;
const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID,
&Invalid);
if (Invalid)
return true;
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);

View File

@ -542,9 +542,13 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
return false;
case tok::angle_string_literal:
case tok::string_literal:
Filename = PP.getSpelling(Tok, FilenameBuffer);
case tok::string_literal: {
bool Invalid = false;
Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid);
if (Invalid)
return false;
break;
}
case tok::less:
// This could be a <foo/bar.h> file coming from a macro expansion. In this

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