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 endif
test:: test::
@ $(MAKE) -C test @ $(MAKE) -C test
report:: report::
@ $(MAKE) -C test report @ $(MAKE) -C test report
@ -27,7 +27,8 @@ clean::
@ $(MAKE) -C test clean @ $(MAKE) -C test clean
tags:: 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: cscope.files:
find tools lib include -name '*.cpp' \ 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 <p>The syntax and high level language feature description is in <a
href="BlockLanguageSpec.txt">BlockLanguageSpec.txt</a>. Implementation and ABI href="BlockLanguageSpec.txt">BlockLanguageSpec.txt</a>. Implementation and ABI
details for the clang implementation are in <a 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> <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>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> <h2 id="objcxx">Objective C++ Language Features</h2>
<!-- ======================================================================= --> <!-- ======================================================================= -->

View File

@ -728,7 +728,8 @@ enum CXCursorKind {
CXCursor_InvalidFile = 70, CXCursor_InvalidFile = 70,
CXCursor_NoDeclFound = 71, CXCursor_NoDeclFound = 71,
CXCursor_NotImplemented = 72, CXCursor_NotImplemented = 72,
CXCursor_LastInvalid = 72, CXCursor_InvalidCode = 73,
CXCursor_LastInvalid = CXCursor_InvalidCode,
/* Expressions */ /* Expressions */
CXCursor_FirstExpr = 100, CXCursor_FirstExpr = 100,
@ -796,7 +797,14 @@ enum CXCursorKind {
CXCursor_IBActionAttr = 401, CXCursor_IBActionAttr = 401,
CXCursor_IBOutletAttr = 402, 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); 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 * \brief Determine whether the given cursor represents a currently
* unexposed piece of the AST (e.g., CXCursor_UnexposedStmt). * unexposed piece of the AST (e.g., CXCursor_UnexposedStmt).

View File

@ -259,19 +259,11 @@ class ASTContext {
/// this ASTContext object. /// this ASTContext object.
LangOptions LangOpts; 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. /// MallocAlloc/BumpAlloc - The allocator objects used to create AST objects.
bool FreeMemory; bool FreeMemory;
llvm::MallocAllocator MallocAlloc; llvm::MallocAllocator MallocAlloc;
llvm::BumpPtrAllocator BumpAlloc; 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: public:
const TargetInfo &Target; const TargetInfo &Target;
IdentifierTable &Idents; IdentifierTable &Idents;
@ -287,10 +279,6 @@ public:
QualType ObjCClassRedefinitionType; QualType ObjCClassRedefinitionType;
QualType ObjCSelRedefinitionType; 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; } SourceManager& getSourceManager() { return SourceMgr; }
const SourceManager& getSourceManager() const { return SourceMgr; } const SourceManager& getSourceManager() const { return SourceMgr; }
void *Allocate(unsigned Size, unsigned Align = 8) { void *Allocate(unsigned Size, unsigned Align = 8) {
@ -357,8 +345,6 @@ public:
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; } TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
const char *getCommentForDecl(const Decl *D);
// Builtin Types. // Builtin Types.
CanQualType VoidTy; CanQualType VoidTy;
CanQualType BoolTy; CanQualType BoolTy;
@ -1161,6 +1147,8 @@ public:
/// Compatibility predicates used to check assignment expressions. /// Compatibility predicates used to check assignment expressions.
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1 bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
bool typesAreBlockPointerCompatible(QualType, QualType);
bool isObjCIdType(QualType T) const { bool isObjCIdType(QualType T) const {
return T == ObjCIdTypedefType; return T == ObjCIdTypedefType;
} }
@ -1179,13 +1167,16 @@ public:
const ObjCObjectPointerType *RHSOPT); const ObjCObjectPointerType *RHSOPT);
bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS, bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
const ObjCInterfaceType *RHS); const ObjCInterfaceType *RHS);
bool canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT);
bool areComparableObjCPointerTypes(QualType LHS, QualType RHS); bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
QualType areCommonBaseCompatible(const ObjCObjectPointerType *LHSOPT, QualType areCommonBaseCompatible(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT); const ObjCObjectPointerType *RHSOPT);
// Functions for calculating composite types // Functions for calculating composite types
QualType mergeTypes(QualType, QualType); QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false);
QualType mergeFunctionTypes(QualType, QualType); QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false);
/// UsualArithmeticConversionsType - handles the various conversions /// UsualArithmeticConversionsType - handles the various conversions
/// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9) /// 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.) /// this ever changes, this operator will have to be changed, too.)
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope): /// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
/// @code /// @code
/// // Default alignment (16) /// // Default alignment (8)
/// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments); /// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments);
/// // Specific alignment /// // Specific alignment
/// IntegerLiteral *Ex2 = new (Context, 8) IntegerLiteral(arguments); /// IntegerLiteral *Ex2 = new (Context, 4) IntegerLiteral(arguments);
/// @endcode /// @endcode
/// Please note that you cannot use delete on the pointer; it must be /// Please note that you cannot use delete on the pointer; it must be
/// deallocated using an explicit destructor call followed by /// 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. /// null on error.
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope): /// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
/// @code /// @code
/// // Default alignment (16) /// // Default alignment (8)
/// char *data = new (Context) char[10]; /// char *data = new (Context) char[10];
/// // Specific alignment /// // Specific alignment
/// char *data = new (Context, 8) char[10]; /// char *data = new (Context, 4) char[10];
/// @endcode /// @endcode
/// Please note that you cannot use delete on the pointer; it must be /// Please note that you cannot use delete on the pointer; it must be
/// deallocated using an explicit destructor call followed by /// 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). /// allocator supports it).
/// @return The allocated memory. Could be NULL. /// @return The allocated memory. Could be NULL.
inline void *operator new[](size_t Bytes, clang::ASTContext& C, 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); return C.Allocate(Bytes, Alignment);
} }

View File

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

View File

@ -58,14 +58,6 @@ public:
virtual ~ExternalASTSource(); 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 /// \brief Resolve a type ID into a type, potentially building a new
/// type. /// type.
virtual QualType GetType(uint32_t ID) = 0; virtual QualType GetType(uint32_t ID) = 0;

View File

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

View File

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

View File

@ -293,4 +293,28 @@ BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_pcmpeqq, "V2LLiV2LLiV2LLi", "") BUILTIN(__builtin_ia32_pcmpeqq, "V2LLiV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16ci", "") 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 #undef BUILTIN

View File

@ -65,9 +65,6 @@ def err_target_invalid_feature : Error<"invalid target feature '%0'">;
// Source manager // Source manager
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; 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< def err_file_modified : Error<
"file '%0' modified since it was first processed">, DefaultFatal; "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>">; "invalid option '%0' not of the form <from-file>;<to-file>">;
def err_drv_invalid_gcc_output_type : Error< def err_drv_invalid_gcc_output_type : Error<
"invalid output type '%0' for use with gcc tool">; "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< def warn_drv_input_file_unused : Warning<
"%0: '%1' input unused when '%2' is present">; "%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'">; "unable to read PCH file: '%0'">;
def err_fe_not_a_pch_file : Error< def err_fe_not_a_pch_file : Error<
"input is not a PCH file: '%0'">; "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< 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< 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< def err_fe_unable_to_open_output : Error<
"unable to open output file '%0': '%1'">; "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< def err_fe_pth_file_has_no_source_header : Error<
"PTH file '%0' does not designate an original source header file for -include-pth">; "PTH file '%0' does not designate an original source header file for -include-pth">;
def warn_fe_macro_contains_embedded_newline : Warning< def warn_fe_macro_contains_embedded_newline : Warning<

View File

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

View File

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

View File

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

View File

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

View File

@ -17,13 +17,15 @@
#include "clang/Basic/Diagnostic.h" #include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.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/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/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallString.h"
#include "llvm/ADT/ImmutableSet.h"
#include <list> #include <list>
namespace clang { namespace clang {
@ -45,7 +47,7 @@ class ParentMap;
// Interface for individual bug reports. // Interface for individual bug reports.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
class BugReporterVisitor { class BugReporterVisitor : public llvm::FoldingSetNode {
public: public:
virtual ~BugReporterVisitor(); virtual ~BugReporterVisitor();
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
@ -53,6 +55,7 @@ public:
BugReporterContext& BRC) = 0; BugReporterContext& BRC) = 0;
virtual bool isOwnedByReporterContext() { return true; } virtual bool isOwnedByReporterContext() { return true; }
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
}; };
// FIXME: Combine this with RangedBugReport and remove RangedBugReport. // FIXME: Combine this with RangedBugReport and remove RangedBugReport.
@ -385,16 +388,18 @@ public:
class BugReporterContext { class BugReporterContext {
GRBugReporter &BR; 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: public:
BugReporterContext(GRBugReporter& br) : BR(br) {} BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.GetEmptyList()) {}
virtual ~BugReporterContext(); virtual ~BugReporterContext();
void addVisitor(BugReporterVisitor* visitor) { void addVisitor(BugReporterVisitor* visitor);
if (visitor) Callbacks.push_back(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_begin() { return Callbacks.begin(); }
visitor_iterator visitor_end() { return Callbacks.end(); } 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, void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
const ExplodedNode *N); const ExplodedNode *N);
void registerNilReceiverVisitor(BugReporterContext &BRC);
} // end namespace clang::bugreporter } // end namespace clang::bugreporter

View File

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

View File

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

View File

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

View File

@ -227,8 +227,6 @@ def code_completion_macros : Flag<"-code-completion-macros">,
HelpText<"Include macros in code-completion results">; HelpText<"Include macros in code-completion results">;
def disable_free : Flag<"-disable-free">, def disable_free : Flag<"-disable-free">,
HelpText<"Disable freeing of memory on exit">; 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">, def help : Flag<"-help">,
HelpText<"Print this help text">; HelpText<"Print this help text">;
def _help : Flag<"--help">, Alias<help>; def _help : Flag<"--help">, Alias<help>;
@ -262,6 +260,8 @@ def analyze : Flag<"-analyze">,
HelpText<"Run static analysis engine">; HelpText<"Run static analysis engine">;
def dump_tokens : Flag<"-dump-tokens">, def dump_tokens : Flag<"-dump-tokens">,
HelpText<"Run preprocessor, dump internal rep of 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">, def parse_noop : Flag<"-parse-noop">,
HelpText<"Run parser with noop callbacks (for timings)">; HelpText<"Run parser with noop callbacks (for timings)">;
def fsyntax_only : Flag<"-fsyntax-only">, def fsyntax_only : Flag<"-fsyntax-only">,
@ -355,10 +355,12 @@ def fno_elide_constructors : Flag<"-fno-elide-constructors">,
HelpText<"Disable C++ copy constructor elision">; HelpText<"Disable C++ copy constructor elision">;
def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, 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">; 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">, def fno_operator_names : Flag<"-fno-operator-names">,
HelpText<"Do not treat C++ operator name keywords as synonyms for operators">; 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">, def fconstant_string_class : Separate<"-fconstant-string-class">,
MetaVarName<"<class name>">, MetaVarName<"<class name>">,
HelpText<"Specify the class to use for constant Objective-C string objects.">; 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">; HelpText<"Undefine the specified macro">;
def undef : Flag<"-undef">, MetaVarName<"<macro>">, def undef : Flag<"-undef">, MetaVarName<"<macro>">,
HelpText<"undef all system defines">; HelpText<"undef all system defines">;
def detailed_preprocessing_record : Flag<"-detailed-preprocessing-record">,
HelpText<"include a detailed record of preprocessing actions">;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Preprocessed Output Options // Preprocessed Output Options
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -83,6 +83,9 @@ public:
/// Name to use when calling the generic gcc. /// Name to use when calling the generic gcc.
std::string CCCGenericGCCName; 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. /// Whether the driver should follow g++ like behavior.
unsigned CCCIsCXX : 1; unsigned CCCIsCXX : 1;
@ -92,6 +95,10 @@ public:
/// Only print tool bindings, don't build any jobs. /// Only print tool bindings, don't build any jobs.
unsigned CCCPrintBindings : 1; 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: private:
/// Whether to check that input files exist when constructing compilation /// Whether to check that input files exist when constructing compilation
/// jobs. /// jobs.

View File

@ -229,6 +229,7 @@ def exported__symbols__list : Separate<"-exported_symbols_list">;
def e : JoinedOrSeparate<"-e">; def e : JoinedOrSeparate<"-e">;
def fPIC : Flag<"-fPIC">, Group<f_Group>; def fPIC : Flag<"-fPIC">, Group<f_Group>;
def fPIE : Flag<"-fPIE">, 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 fapple_kext : Flag<"-fapple-kext">, Group<f_Group>;
def fasm_blocks : Flag<"-fasm-blocks">, Group<clang_ignored_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>; 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 fencoding_EQ : Joined<"-fencoding=">, Group<f_Group>;
def fexceptions : Flag<"-fexceptions">, Group<f_Group>; def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
def fextdirs_EQ : Joined<"-fextdirs=">, 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 ffreestanding : Flag<"-ffreestanding">, Group<f_Group>;
def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>; def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>;
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; 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 fmudflap : Flag<"-fmudflap">, Group<f_Group>;
def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>; def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>;
def fnext_runtime : Flag<"-fnext-runtime">, 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_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_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, Group<f_Group>;
def fno_blocks : Flag<"-fno-blocks">, 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_functions : Flag<"-fno-inline-functions">, Group<clang_ignored_f_Group>;
def fno_inline : Flag<"-fno-inline">, 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_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_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, 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>; 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_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>;
def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<clang_ignored_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_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_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_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>;
def fno_working_directory : Flag<"-fno-working-directory">, 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_bitfields : Flag<"-funsigned-bitfields">, Group<f_Group>;
def funsigned_char : Flag<"-funsigned-char">, Group<f_Group>; def funsigned_char : Flag<"-funsigned-char">, Group<f_Group>;
def funwind_tables : Flag<"-funwind-tables">, 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 fverbose_asm : Flag<"-fverbose-asm">, Group<f_Group>;
def fvisibility_EQ : Joined<"-fvisibility=">, Group<f_Group>; def fvisibility_EQ : Joined<"-fvisibility=">, Group<f_Group>;
def fwritable_strings : Flag<"-fwritable-strings">, 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 iwithsysroot : JoinedOrSeparate<"-iwithsysroot">, Group<i_Group>;
def i : Joined<"-i">, Group<i_Group>; def i : Joined<"-i">, Group<i_Group>;
def keep__private__externs : Flag<"-keep_private_externs">; 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 m32 : Flag<"-m32">, Group<m_Group>, Flags<[DriverOption]>;
def m3dnowa : Flag<"-m3dnowa">, Group<m_x86_Features_Group>; def m3dnowa : Flag<"-m3dnowa">, Group<m_x86_Features_Group>;
def m3dnow : Flag<"-m3dnow">, 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 #ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
#define LLVM_CLANG_FRONTEND_ASTUNIT_H #define LLVM_CLANG_FRONTEND_ASTUNIT_H
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManager.h"
#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/OwningPtr.h"
#include "clang/Basic/FileManager.h" #include "clang/Basic/FileManager.h"
#include "clang/Index/ASTLocation.h" #include "clang/Index/ASTLocation.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/System/Path.h" #include "llvm/System/Path.h"
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <cassert> #include <cassert>
@ -46,6 +48,11 @@ using namespace idx;
/// \brief Utility class for loading a ASTContext from a PCH file. /// \brief Utility class for loading a ASTContext from a PCH file.
/// ///
class ASTUnit { class ASTUnit {
public:
typedef std::map<FileID, std::vector<PreprocessedEntity *> >
PreprocessedEntitiesByFileMap;
private:
FileManager FileMgr; FileManager FileMgr;
SourceManager SourceMgr; SourceManager SourceMgr;
@ -53,7 +60,7 @@ class ASTUnit {
llvm::OwningPtr<TargetInfo> Target; llvm::OwningPtr<TargetInfo> Target;
llvm::OwningPtr<Preprocessor> PP; llvm::OwningPtr<Preprocessor> PP;
llvm::OwningPtr<ASTContext> Ctx; llvm::OwningPtr<ASTContext> Ctx;
/// Optional owned invocation, just used to make the invocation used in /// Optional owned invocation, just used to make the invocation used in
/// LoadFromCommandLine available. /// LoadFromCommandLine available.
llvm::OwningPtr<CompilerInvocation> Invocation; llvm::OwningPtr<CompilerInvocation> Invocation;
@ -89,6 +96,15 @@ class ASTUnit {
/// destroyed. /// destroyed.
llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles; 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 /// \brief Simple hack to allow us to assert that ASTUnit is not being
/// used concurrently, which is not supported. /// used concurrently, which is not supported.
/// ///
@ -162,6 +178,12 @@ public:
return TopLevelDecls; 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 // Retrieve the diagnostics associated with this AST
typedef const StoredDiagnostic * diag_iterator; typedef const StoredDiagnostic * diag_iterator;
diag_iterator diag_begin() const { return Diagnostics.begin(); } diag_iterator diag_begin() const { return Diagnostics.begin(); }

View File

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

View File

@ -17,6 +17,22 @@
namespace clang { namespace clang {
class FixItRewriter; 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 // AST Consumer Actions
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

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

View File

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

View File

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

View File

@ -33,6 +33,7 @@ namespace clang {
class ASTContext; class ASTContext;
class LabelStmt; class LabelStmt;
class MacroDefinition;
class MemorizeStatCalls; class MemorizeStatCalls;
class Preprocessor; class Preprocessor;
class Sema; class Sema;
@ -160,6 +161,14 @@ private:
/// defined. /// defined.
llvm::DenseMap<const IdentifierInfo *, uint64_t> MacroOffsets; 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 /// \brief Declarations encountered that might be external
/// definitions. /// definitions.
/// ///
@ -206,7 +215,6 @@ private:
const Preprocessor &PP, const Preprocessor &PP,
const char* isysroot); const char* isysroot);
void WritePreprocessor(const Preprocessor &PP); void WritePreprocessor(const Preprocessor &PP);
void WriteComments(ASTContext &Context);
void WriteType(QualType T); void WriteType(QualType T);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
uint64_t WriteDeclContextVisibleBlock(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 /// \param isysroot if non-NULL, write a relocatable PCH file whose headers
/// are relative to the given system root. /// 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, void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const char* isysroot); const char* isysroot);
@ -269,6 +280,10 @@ public:
return MacroOffsets[II]; 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. /// \brief Emit a reference to a type.
void AddTypeRef(QualType T, RecordData &Record); void AddTypeRef(QualType T, RecordData &Record);

View File

@ -36,6 +36,10 @@ public:
unsigned UsePredefines : 1; /// Initialize the preprocessor with the compiler unsigned UsePredefines : 1; /// Initialize the preprocessor with the compiler
/// and target specific predefines. /// 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. /// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude; std::string ImplicitPCHInclude;
@ -77,7 +81,7 @@ public:
} }
public: public:
PreprocessorOptions() : UsePredefines(true) {} PreprocessorOptions() : UsePredefines(true), DetailedRecord(false) {}
void addMacroDef(llvm::StringRef Name) { void addMacroDef(llvm::StringRef Name) {
Macros.push_back(std::make_pair(Name, false)); 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 /// ProcessWarningOptions - Initialize the diagnostic client and process the
/// warning options specified on the command line. /// 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. /// DoPrintPreprocessedInput - Implement -E mode.
void DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream* OS, void DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream* OS,

View File

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

View File

@ -214,9 +214,10 @@ public:
void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; } void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
typedef std::vector<HeaderFileInfo>::iterator header_file_iterator; typedef std::vector<HeaderFileInfo>::const_iterator header_file_iterator;
header_file_iterator header_file_begin() { return FileInfo.begin(); } header_file_iterator header_file_begin() const { return FileInfo.begin(); }
header_file_iterator header_file_end() { return FileInfo.end(); } header_file_iterator header_file_end() const { return FileInfo.end(); }
unsigned header_file_size() const { return FileInfo.size(); }
// Used by PCHReader. // Used by PCHReader.
void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID); 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 TargetInfo;
class PPCallbacks; class PPCallbacks;
class DirectoryLookup; class DirectoryLookup;
class PreprocessingRecord;
/// Preprocessor - This object engages in a tight little dance with the lexer to /// Preprocessor - This object engages in a tight little dance with the lexer to
/// efficiently preprocess tokens. Lexers know only about tokens within a /// efficiently preprocess tokens. Lexers know only about tokens within a
/// single source file, and don't know anything about preprocessor-level issues /// single source file, and don't know anything about preprocessor-level issues
@ -209,6 +210,13 @@ class Preprocessor {
unsigned NumCachedTokenLexers; unsigned NumCachedTokenLexers;
TokenLexer *TokenLexerCache[TokenLexerCacheSize]; 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. private: // Cached tokens state.
typedef llvm::SmallVector<Token, 1> CachedTokensTy; typedef llvm::SmallVector<Token, 1> CachedTokensTy;
@ -348,9 +356,17 @@ public:
/// It is an error to remove a handler that has not been registered. /// It is an error to remove a handler that has not been registered.
void RemoveCommentHandler(CommentHandler *Handler); 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, /// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc. /// which implicitly adds the builtin defines etc.
void EnterMainSourceFile(); bool EnterMainSourceFile();
/// EnterSourceFile - Add a source file to the top of the include stack and /// 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 /// 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 // Otherwise, fall back on getCharacterData, which is slower, but always
// works. // works.
return *SourceMgr.getCharacterData(Tok.getLocation()); return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid);
} }
/// CreateString - Plop the specified string into a scratch buffer and set the /// 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. /// an empty string if not. This is used for pretty crash reporting.
virtual std::string getDeclName(DeclPtrTy D) { return ""; } 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. // Declaration Tracking Callbacks.
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
@ -727,9 +723,17 @@ public:
/// ActOnTagFinishDefinition - Invoked once we have finished parsing /// ActOnTagFinishDefinition - Invoked once we have finished parsing
/// the definition of a tag (enumeration, class, struct, or union). /// 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, virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
SourceLocation RBraceLoc) { } 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, virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl,
DeclPtrTy LastEnumConstant, DeclPtrTy LastEnumConstant,
SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation IdLoc, IdentifierInfo *Id,

View File

@ -90,7 +90,6 @@ class Parser {
llvm::OwningPtr<PragmaHandler> PackHandler; llvm::OwningPtr<PragmaHandler> PackHandler;
llvm::OwningPtr<PragmaHandler> UnusedHandler; llvm::OwningPtr<PragmaHandler> UnusedHandler;
llvm::OwningPtr<PragmaHandler> WeakHandler; llvm::OwningPtr<PragmaHandler> WeakHandler;
llvm::OwningPtr<clang::CommentHandler> CommentHandler;
/// Whether the '>' token acts as an operator or not. This will be /// Whether the '>' token acts as an operator or not. This will be
/// true except when we are parsing an expression within a C++ /// 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), GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0),
ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
SourceMgr(SM), LangOpts(LOpts), SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t),
LoadedExternalComments(false), FreeMemory(FreeMem), Target(t),
Idents(idents), Selectors(sels), Idents(idents), Selectors(sels),
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
ObjCIdRedefinitionType = QualType(); 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 // Type Sizing and Analysis
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -4315,6 +4119,41 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
return false; 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 /// getIntersectionOfProtocols - This routine finds the intersection of set
/// of protocols inherited from two distinct objective-c pointer objects. /// of protocols inherited from two distinct objective-c pointer objects.
/// It is used to build composite qualifier list of the composite type of /// 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(); 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 *lbase = lhs->getAs<FunctionType>();
const FunctionType *rbase = rhs->getAs<FunctionType>(); const FunctionType *rbase = rhs->getAs<FunctionType>();
const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase); const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase);
@ -4460,7 +4304,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
bool allRTypes = true; bool allRTypes = true;
// Check return type // 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 (retType.isNull()) return QualType();
if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType())) if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType()))
allLTypes = false; allLTypes = false;
@ -4500,7 +4348,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
for (unsigned i = 0; i < lproto_nargs; i++) { for (unsigned i = 0; i < lproto_nargs; i++) {
QualType largtype = lproto->getArgType(i).getUnqualifiedType(); QualType largtype = lproto->getArgType(i).getUnqualifiedType();
QualType rargtype = rproto->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(); if (argtype.isNull()) return QualType();
types.push_back(argtype); types.push_back(argtype);
if (getCanonicalType(argtype) != getCanonicalType(largtype)) if (getCanonicalType(argtype) != getCanonicalType(largtype))
@ -4554,7 +4402,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
return getFunctionNoProtoType(retType, NoReturn, lcc); 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 // 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 // type is adjusted to "T" prior to any further analysis, the expression
// designates the object or function denoted by the reference, and the // 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 // Merge two block pointer types, while trying to preserve typedef info
QualType LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType(); QualType LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType();
QualType RHSPointee = RHS->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 (ResultType.isNull()) return QualType();
if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType))
return LHS; return LHS;
@ -4732,7 +4581,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
ArrayType::ArraySizeModifier(), 0); ArrayType::ArraySizeModifier(), 0);
} }
case Type::FunctionNoProto: case Type::FunctionNoProto:
return mergeFunctionTypes(LHS, RHS); return mergeFunctionTypes(LHS, RHS, OfBlockPointer);
case Type::Record: case Type::Record:
case Type::Enum: case Type::Enum:
return QualType(); return QualType();
@ -4761,12 +4610,19 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return QualType(); return QualType();
} }
case Type::ObjCObjectPointer: { case Type::ObjCObjectPointer: {
if (OfBlockPointer) {
if (canAssignObjCInterfacesInBlockPointer(
LHS->getAs<ObjCObjectPointerType>(),
RHS->getAs<ObjCObjectPointerType>()))
return LHS;
return QualType();
}
if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(), if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(),
RHS->getAs<ObjCObjectPointerType>())) RHS->getAs<ObjCObjectPointerType>()))
return LHS; return LHS;
return QualType(); return QualType();
} }
} }
return QualType(); return QualType();

View File

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

View File

@ -743,7 +743,10 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
} }
ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const { 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); llvm::raw_svector_ostream Out(Name);
Out << (MD->isInstanceMethod() ? '-' : '+'); Out << (MD->isInstanceMethod() ? '-' : '+');
Out << '['; 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 = if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) { dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) {
Out << '('; Out << '(';
@ -1104,11 +1109,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (m->isArrow()) if (m->isArrow())
return LV_Valid; return LV_Valid;
Expr *BaseExp = m->getBase(); Expr *BaseExp = m->getBase();
if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass ||
BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass)
return LV_SubObjCPropertySetting; return LV_SubObjCPropertySetting;
return return
(BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass) ? BaseExp->isLvalue(Ctx);
LV_SubObjCPropertyGetterSetting : BaseExp->isLvalue(Ctx);
} }
case UnaryOperatorClass: case UnaryOperatorClass:
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref) if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
@ -1324,8 +1329,6 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
return MLV_InvalidExpression; return MLV_InvalidExpression;
case LV_MemberFunction: return MLV_MemberFunction; case LV_MemberFunction: return MLV_MemberFunction;
case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
case LV_SubObjCPropertyGetterSetting:
return MLV_SubObjCPropertyGetterSetting;
case LV_ClassTemporary: case LV_ClassTemporary:
return MLV_ClassTemporary; return MLV_ClassTemporary;
} }

View File

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

View File

@ -18,6 +18,7 @@
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "clang/AST/PrettyPrinter.h" #include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/LangOptions.h" #include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
using namespace clang; using namespace clang;
@ -412,10 +413,12 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
return; return;
std::string Buffer; std::string Buffer;
bool HasKindDecoration = false;
// We don't print tags unless this is an elaborated type. // We don't print tags unless this is an elaborated type.
// In C, we just assume every RecordType is an elaborated type. // In C, we just assume every RecordType is an elaborated type.
if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) { if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) {
HasKindDecoration = true;
Buffer += D->getKindName(); Buffer += D->getKindName();
Buffer += ' '; Buffer += ' ';
} }
@ -425,15 +428,31 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
// this will always be empty. // this will always be empty.
AppendScope(D->getDeclContext(), Buffer); AppendScope(D->getDeclContext(), Buffer);
const char *ID;
if (const IdentifierInfo *II = D->getIdentifier()) if (const IdentifierInfo *II = D->getIdentifier())
ID = II->getNameStart(); Buffer += II->getNameStart();
else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) { else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) {
assert(Typedef->getIdentifier() && "Typedef without identifier?"); assert(Typedef->getIdentifier() && "Typedef without identifier?");
ID = Typedef->getIdentifier()->getNameStart(); Buffer += Typedef->getIdentifier()->getNameStart();
} else } else {
ID = "<anonymous>"; // Make an unambiguous representation for anonymous types, e.g.
Buffer += ID; // <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 // If this is a class template specialization, print the template
// arguments. // arguments.

View File

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

View File

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

View File

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

View File

@ -36,6 +36,23 @@ BugReporterContext::~BugReporterContext() {
if ((*I)->isOwnedByReporterContext()) delete *I; 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. // Helper routines for walking the ExplodedGraph and fetching statements.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -1613,7 +1630,9 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
else else
return; return;
// Register node visitors.
R->registerInitialVisitors(PDB, N); R->registerInitialVisitors(PDB, N);
bugreporter::registerNilReceiverVisitor(PDB);
switch (PDB.getGenerationScheme()) { switch (PDB.getGenerationScheme()) {
case PathDiagnosticClient::Extensive: case PathDiagnosticClient::Extensive:

View File

@ -92,6 +92,13 @@ public:
FindLastStoreBRVisitor(SVal v, const MemRegion *r) FindLastStoreBRVisitor(SVal v, const MemRegion *r)
: R(r), V(v), satisfied(false), StoreSite(0) {} : 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, PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN, const ExplodedNode *PrevN,
BugReporterContext& BRC) { BugReporterContext& BRC) {
@ -129,8 +136,8 @@ public:
return NULL; return NULL;
satisfied = true; satisfied = true;
std::string sbuf; llvm::SmallString<256> sbuf;
llvm::raw_string_ostream os(sbuf); llvm::raw_svector_ostream os(sbuf);
if (const PostStmt *PS = N->getLocationAs<PostStmt>()) { if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
@ -239,6 +246,13 @@ public:
TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
: Constraint(constraint), Assumption(assumption), isSatisfied(false) {} : 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, PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN, const ExplodedNode *PrevN,
BugReporterContext& BRC) { BugReporterContext& BRC) {
@ -365,3 +379,52 @@ void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC,
BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); 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 class CallAndMessageChecker
: public CheckerVisitor<CallAndMessageChecker> { : public CheckerVisitor<CallAndMessageChecker> {
BugType *BT_call_null; BugType *BT_call_null;
BugType *BT_call_undef; BugType *BT_call_undef;
BugType *BT_call_arg; BugType *BT_call_arg;
BugType *BT_msg_undef; BugType *BT_msg_undef;
BugType *BT_msg_arg; BugType *BT_msg_arg;
@ -44,12 +44,20 @@ public:
bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME); bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
private: private:
bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
const char *BT_desc, BugType *&BT);
void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME, void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
ExplodedNode *N); ExplodedNode *N);
void HandleNilReceiver(CheckerContext &C, const GRState *state, 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 } // end anonymous namespace
@ -62,19 +70,127 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
ExplodedNode *N = C.GenerateSink(); ExplodedNode *N = C.GenerateSink();
if (!N) if (!N)
return; return;
EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetCalleeExpr(N)); bugreporter::GetCalleeExpr(N));
C.EmitReport(R); 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 CallExpr *CE){
const Expr *Callee = CE->getCallee()->IgnoreParens(); const Expr *Callee = CE->getCallee()->IgnoreParens();
SVal L = C.getState()->getSVal(Callee); SVal L = C.getState()->getSVal(Callee);
if (L.isUndef()) { if (L.isUndef()) {
if (!BT_call_undef) if (!BT_call_undef)
BT_call_undef = BT_call_undef =
@ -82,31 +198,20 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
EmitBadCall(BT_call_undef, C, CE); EmitBadCall(BT_call_undef, C, CE);
return; return;
} }
if (isa<loc::ConcreteInt>(L)) { if (isa<loc::ConcreteInt>(L)) {
if (!BT_call_null) if (!BT_call_null)
BT_call_null = BT_call_null =
new BuiltinBug("Called function pointer is null (null dereference)"); new BuiltinBug("Called function pointer is null (null dereference)");
EmitBadCall(BT_call_null, C, CE); 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, void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
@ -132,23 +237,11 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
// Check for any arguments that are uninitialized/undefined. // Check for any arguments that are uninitialized/undefined.
for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(), for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
E = ME->arg_end(); I != E; ++I) { E = ME->arg_end(); I != E; ++I)
if (state->getSVal(*I).isUndef()) { if (PreVisitProcessArg(C, *I,
if (ExplodedNode *N = C.GenerateSink()) { "Pass-by-value argument in message expression "
if (!BT_msg_arg) "is undefined", 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);
return; return;
}
}
}
} }
bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C, bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
@ -160,24 +253,24 @@ bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
const ObjCMessageExpr *ME, const ObjCMessageExpr *ME,
ExplodedNode *N) { ExplodedNode *N) {
if (!BT_msg_ret) if (!BT_msg_ret)
BT_msg_ret = BT_msg_ret =
new BuiltinBug("Receiver in message expression is " new BuiltinBug("Receiver in message expression is "
"'nil' and returns a garbage value"); "'nil' and returns a garbage value");
llvm::SmallString<200> buf; llvm::SmallString<200> buf;
llvm::raw_svector_ostream os(buf); llvm::raw_svector_ostream os(buf);
os << "The receiver of message '" << ME->getSelector().getAsString() os << "The receiver of message '" << ME->getSelector().getAsString()
<< "' is nil and returns a value of type '" << "' is nil and returns a value of type '"
<< ME->getType().getAsString() << "' that will be garbage"; << ME->getType().getAsString() << "' that will be garbage";
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N); EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
const Expr *receiver = ME->getReceiver(); const Expr *receiver = ME->getReceiver();
report->addRange(receiver->getSourceRange()); report->addRange(receiver->getSourceRange());
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
receiver); receiver);
C.EmitReport(report); C.EmitReport(report);
} }
static bool SupportsNilWithFloatRet(const llvm::Triple &triple) { static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
@ -188,11 +281,11 @@ static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
const GRState *state, const GRState *state,
const ObjCMessageExpr *ME) { const ObjCMessageExpr *ME) {
// Check the return type of the message expression. A message to nil will // Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture. // return different values depending on the return type and the architecture.
QualType RetTy = ME->getType(); QualType RetTy = ME->getType();
ASTContext &Ctx = C.getASTContext(); ASTContext &Ctx = C.getASTContext();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
@ -216,7 +309,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
if (CanRetTy != Ctx.VoidTy && if (CanRetTy != Ctx.VoidTy &&
C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
// Compute: sizeof(void *) and sizeof(return type) // 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); const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
if (voidPtrSize < returnTypeSize && if (voidPtrSize < returnTypeSize &&
@ -247,6 +340,6 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
C.GenerateNode(state->BindExpr(ME, V)); C.GenerateNode(state->BindExpr(ME, V));
return; return;
} }
C.addTransition(state); C.addTransition(state);
} }

View File

@ -220,16 +220,25 @@ public:
if (E->isConstantInitializer(Ctx)) if (E->isConstantInitializer(Ctx))
return; 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 (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() && 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()); Report(V, DeadInit, V->getLocation(), E->getSourceRange());
} }

View File

@ -44,7 +44,9 @@ public:
} }
SVal ArrayToPointer(Loc Array); 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){ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){
return store; return store;
} }

View File

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

View File

@ -35,6 +35,7 @@ GRStateManager::~GRStateManager() {
const GRState* const GRState*
GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper) { SymbolReaper& SymReaper) {
// This code essentially performs a "mark-and-sweep" of the VariableBindings. // This code essentially performs a "mark-and-sweep" of the VariableBindings.
@ -50,7 +51,7 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
state, RegionRoots); state, RegionRoots);
// Clean up the store. // Clean up the store.
NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, SymReaper, NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, LCtx, SymReaper,
RegionRoots); RegionRoots);
return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState), 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. /// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed. /// 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); llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
const GRState *EnterStackFrame(const GRState *state, const GRState *EnterStackFrame(const GRState *state,
@ -1678,12 +1680,14 @@ class RemoveDeadBindingsWorker :
llvm::SmallVector<const SymbolicRegion*, 12> Postponed; llvm::SmallVector<const SymbolicRegion*, 12> Postponed;
SymbolReaper &SymReaper; SymbolReaper &SymReaper;
Stmt *Loc; Stmt *Loc;
const StackFrameContext *CurrentLCtx;
public: public:
RemoveDeadBindingsWorker(RegionStoreManager &rm, GRStateManager &stateMgr, RemoveDeadBindingsWorker(RegionStoreManager &rm, GRStateManager &stateMgr,
RegionBindings b, SymbolReaper &symReaper, RegionBindings b, SymbolReaper &symReaper,
Stmt *loc) Stmt *loc, const StackFrameContext *LCtx)
: ClusterAnalysis<RemoveDeadBindingsWorker>(rm, stateMgr, b), : ClusterAnalysis<RemoveDeadBindingsWorker>(rm, stateMgr, b),
SymReaper(symReaper), Loc(loc) {} SymReaper(symReaper), Loc(loc), CurrentLCtx(LCtx) {}
// Called by ClusterAnalysis. // Called by ClusterAnalysis.
void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C); void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C);
@ -1713,6 +1717,15 @@ void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
return; 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, void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
@ -1799,11 +1812,12 @@ bool RemoveDeadBindingsWorker::UpdatePostponed() {
} }
Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper, SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{ {
RegionBindings B = GetRegionBindings(store); RegionBindings B = GetRegionBindings(store);
RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc); RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc, LCtx);
W.GenerateClusters(); W.GenerateClusters();
// Enqueue the region roots onto the worklist. // Enqueue the region roots onto the worklist.

View File

@ -25,17 +25,47 @@ using namespace clang;
using namespace CodeGen; using namespace CodeGen;
using namespace llvm; 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 /// Utility to insert an atomic instruction based on Instrinsic::ID
/// and the expression node. /// and the expression node.
static RValue EmitBinaryAtomic(CodeGenFunction& CGF, static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
Intrinsic::ID Id, const CallExpr *E) { Intrinsic::ID Id, const CallExpr *E) {
Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
CGF.EmitScalarExpr(E->getArg(1)) };
const llvm::Type *ResType[2]; const llvm::Type *ResType[2];
ResType[0] = CGF.ConvertType(E->getType()); ResType[0] = CGF.ConvertType(E->getType());
ResType[1] = CGF.ConvertType(E->getArg(0)->getType()); ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2); Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
return RValue::get(CGF.Builder.CreateCall2(AtomF, return RValue::get(EmitCallWithBarrier(CGF, AtomF, Args, Args + 2));
CGF.EmitScalarExpr(E->getArg(0)),
CGF.EmitScalarExpr(E->getArg(1))));
} }
/// Utility to insert an atomic instruction based Instrinsic::ID and /// 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[0] = CGF.ConvertType(E->getType());
ResType[1] = CGF.ConvertType(E->getArg(0)->getType()); ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2); Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
Value *Ptr = CGF.EmitScalarExpr(E->getArg(0)); Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
Value *Operand = CGF.EmitScalarExpr(E->getArg(1)); CGF.EmitScalarExpr(E->getArg(1)) };
Value *Result = CGF.Builder.CreateCall2(AtomF, Ptr, Operand); Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2);
if (Id == Intrinsic::atomic_load_nand) if (Id == Intrinsic::atomic_load_nand)
Result = CGF.Builder.CreateNot(Result); Result = CGF.Builder.CreateNot(Result);
return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Args[1]));
return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Operand));
} }
static llvm::ConstantInt *getInt32(llvm::LLVMContext &Context, int32_t Value) { 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_2:
case Builtin::BI__sync_val_compare_and_swap_4: 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_8:
case Builtin::BI__sync_val_compare_and_swap_16: case Builtin::BI__sync_val_compare_and_swap_16: {
{
const llvm::Type *ResType[2]; const llvm::Type *ResType[2];
ResType[0]= ConvertType(E->getType()); ResType[0]= ConvertType(E->getType());
ResType[1] = ConvertType(E->getArg(0)->getType()); ResType[1] = ConvertType(E->getArg(0)->getType());
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2); Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
return RValue::get(Builder.CreateCall3(AtomF, Value *Args[3] = { EmitScalarExpr(E->getArg(0)),
EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)),
EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2)) };
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_1:
case Builtin::BI__sync_bool_compare_and_swap_2: 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_4:
case Builtin::BI__sync_bool_compare_and_swap_8: 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]; const llvm::Type *ResType[2];
ResType[0]= ConvertType(E->getArg(1)->getType()); ResType[0]= ConvertType(E->getArg(1)->getType());
ResType[1] = llvm::PointerType::getUnqual(ResType[0]); ResType[1] = llvm::PointerType::getUnqual(ResType[0]);
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2); Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
Value *OldVal = EmitScalarExpr(E->getArg(1)); Value *OldVal = EmitScalarExpr(E->getArg(1));
Value *PrevVal = Builder.CreateCall3(AtomF, Value *Args[3] = { EmitScalarExpr(E->getArg(0)),
EmitScalarExpr(E->getArg(0)), OldVal,
OldVal, EmitScalarExpr(E->getArg(2)) };
EmitScalarExpr(E->getArg(2))); Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args, Args + 3);
Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal); Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal);
// zext bool to int. // zext bool to int.
return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType()))); 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_8:
case Builtin::BI__sync_lock_test_and_set_16: case Builtin::BI__sync_lock_test_and_set_16:
return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E); return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E);
case Builtin::BI__sync_lock_release_1: case Builtin::BI__sync_lock_release_1:
case Builtin::BI__sync_lock_release_2: case Builtin::BI__sync_lock_release_2:
case Builtin::BI__sync_lock_release_4: case Builtin::BI__sync_lock_release_4:
@ -638,10 +666,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
} }
case Builtin::BI__sync_synchronize: { case Builtin::BI__sync_synchronize: {
Value *C[5]; // We assume like gcc appears to, that this only applies to cached memory.
C[0] = C[1] = C[2] = C[3] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 1); EmitMemoryBarrier(*this, true, true, true, true, false);
C[4] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0);
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5);
return RValue::get(0); return RValue::get(0);
} }

View File

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

View File

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

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "CodeGenFunction.h" #include "CodeGenFunction.h"
#include "clang/CodeGen/CodeGenOptions.h"
using namespace clang; using namespace clang;
using namespace CodeGen; using namespace CodeGen;
@ -64,7 +65,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
DeclPtr = llvm::Constant::getNullValue(Int8PtrTy); DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
} else } else
DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
} }
@ -92,6 +93,12 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
void void
CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Constant *DeclPtr) { 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 = const llvm::Type *Int8PtrTy =
llvm::Type::getInt8Ty(VMContext)->getPointerTo(); llvm::Type::getInt8Ty(VMContext)->getPointerTo();
@ -150,10 +157,9 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
false); false);
// Create our global initialization function. // Create our global initialization function.
// FIXME: Should this be tweakable by targets?
llvm::Function *Fn = llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
"__cxx_global_initialization", &TheModule); "_GLOBAL__I_a", &TheModule);
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
&CXXGlobalInits[0], &CXXGlobalInits[0],
@ -161,6 +167,28 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
AddGlobalCtor(Fn); 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, void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D) { const VarDecl *D) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
@ -184,6 +212,20 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
FinishFunction(); 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) { static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) {
// int __cxa_guard_acquire(__int64_t *guard_object); // 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 *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
llvm::SmallVector<llvm::Value*, 8> Args;
Args.clear();
SelectorArgs.push_back(Exc); SelectorArgs.push_back(Exc);
SelectorArgs.push_back(Personality); SelectorArgs.push_back(Personality);
@ -584,12 +582,11 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even // We are required to emit this call to satisfy LLVM, even
// though we don't use the result. // though we don't use the result.
Args.clear(); llvm::Value *Args[] = {
Args.push_back(Exc); Exc, Personality,
Args.push_back(Personality); llvm::ConstantInt::getNullValue(llvm::Type::getInt32Ty(VMContext))
Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), };
0)); Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
Builder.CreateStore(Exc, RethrowPtr); Builder.CreateStore(Exc, RethrowPtr);
EmitBranchThroughCleanup(FinallyRethrow); EmitBranchThroughCleanup(FinallyRethrow);
@ -600,7 +597,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
Builder.CreateInvoke(getEndCatchFn(*this), Builder.CreateInvoke(getEndCatchFn(*this),
Cont, TerminateHandler, Cont, TerminateHandler,
Args.begin(), Args.begin()); &Args[0], &Args[0]);
EmitBlock(Cont); EmitBlock(Cont);
if (Info.SwitchBlock) if (Info.SwitchBlock)
EmitBlock(Info.SwitchBlock); EmitBlock(Info.SwitchBlock);
@ -677,12 +674,8 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
// C string type. Used in lots of places. // C string type. Used in lots of places.
PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
llvm::SmallVector<llvm::Value*, 8> Args; llvm::Value *Args[] = { Exc, Personality, Null };
Args.clear(); CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
Args.push_back(Exc);
Args.push_back(Personality);
Args.push_back(Null);
CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
CGF.EmitBlock(CleanupEntryBB); CGF.EmitBlock(CleanupEntryBB);
@ -731,12 +724,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even // We are required to emit this call to satisfy LLVM, even
// though we don't use the result. // though we don't use the result.
llvm::SmallVector<llvm::Value*, 8> Args; llvm::Value *Args[] = {
Args.push_back(Exc); Exc, Personality,
Args.push_back(Personality); llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)
Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), };
1)); Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
llvm::CallInst *TerminateCall = llvm::CallInst *TerminateCall =
Builder.CreateCall(getTerminateFn(*this)); Builder.CreateCall(getTerminateFn(*this));
TerminateCall->setDoesNotReturn(); TerminateCall->setDoesNotReturn();

View File

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

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SetVector.h"
#include "llvm/Support/Compiler.h" #include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h" #include "llvm/Support/Format.h"
#include <algorithm>
#include <cstdio> #include <cstdio>
using namespace clang; using namespace clang;
@ -1147,6 +1148,12 @@ private:
ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { } ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } 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. /// MethodInfo - Contains information about a method in a vtable.
@ -1191,6 +1198,12 @@ private:
ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { } ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { }
bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } 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 /// ThunkInfo - The 'this' pointer adjustment as well as an optional return
@ -1206,8 +1219,12 @@ private:
ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return) ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
: This(This), Return(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; typedef llvm::DenseMap<uint64_t, ThunkInfo> ThunksInfoMapTy;
@ -1215,6 +1232,16 @@ private:
/// Thunks - The thunks by vtable index in the vtable currently being built. /// Thunks - The thunks by vtable index in the vtable currently being built.
ThunksInfoMapTy Thunks; 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 /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
/// part of the vtable we're currently building. /// part of the vtable we're currently building.
void ComputeThisAdjustments(); void ComputeThisAdjustments();
@ -1330,6 +1357,20 @@ public:
void dumpLayout(llvm::raw_ostream&); 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 /// OverridesMethodInBases - Checks whether whether this virtual member
/// function overrides a member function in any of the given bases. /// function overrides a member function in any of the given bases.
/// Returns the overridden member function, or null if none was found. /// 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. // Add an adjustment for the deleting destructor as well.
Thunks[VtableIndex + 1].This = ThisAdjustment; Thunks[VtableIndex + 1].This = ThisAdjustment;
} }
AddThunk(Overrider.Method, Thunks[VtableIndex]);
} }
/// Clear the method info map. /// Clear the method info map.
@ -2182,20 +2225,25 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << '\n'; Out << '\n';
if (!isBuildingConstructorVtable() && MostDerivedClass->getNumVBases()) { if (isBuildingConstructorVtable())
Out << "Virtual base offset offsets for '"; return;
Out << MostDerivedClass->getQualifiedNameAsString() << "'.\n";
if (MostDerivedClass->getNumVBases()) {
// We store the virtual base class names and their offsets in a map to get // We store the virtual base class names and their offsets in a map to get
// a stable order. // a stable order.
std::map<std::string, int64_t> ClassNamesAndOffsets;
std::map<std::string, int64_t> ClassNamesAndOffsets;
for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(),
E = VBaseOffsetOffsets.end(); I != E; ++I) { E = VBaseOffsetOffsets.end(); I != E; ++I) {
std::string ClassName = I->first->getQualifiedNameAsString(); std::string ClassName = I->first->getQualifiedNameAsString();
int64_t OffsetOffset = I->second; int64_t OffsetOffset = I->second;
ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); 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 = for (std::map<std::string, int64_t>::const_iterator I =
ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end();
@ -2204,6 +2252,52 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << "\n"; 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, llvm::Constant **Decls,
unsigned NumDecls); 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 GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D);
void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E); void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);

View File

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

View File

@ -73,7 +73,7 @@ namespace CodeGen {
class CodeGenFunction; class CodeGenFunction;
class CGDebugInfo; class CGDebugInfo;
class CGObjCRuntime; class CGObjCRuntime;
class MangleBuffer;
/// CodeGenModule - This class organizes the cross-function state that is used /// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code. /// while generating LLVM code.
@ -103,38 +103,16 @@ class CodeGenModule : public BlockModule {
llvm::Function *MemMoveFn; llvm::Function *MemMoveFn;
llvm::Function *MemSetFn; 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 // 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 // a weakref so far. This is used to remove the weak of the reference if we ever
// see a direct reference or a definition. // see a direct reference or a definition.
llvm::SmallPtrSet<llvm::GlobalValue*, 10> WeakRefReferences; 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 /// DeferredDecls - This contains all the decls which have definitions but
/// which are deferred for emission and therefore should only be output if /// 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 /// 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. /// not been referenced yet.
llvm::DenseMap<const char*, GlobalDecl> DeferredDecls; llvm::StringMap<GlobalDecl> DeferredDecls;
/// DeferredDeclsToEmit - This is a list of deferred decls which we have seen /// DeferredDeclsToEmit - This is a list of deferred decls which we have seen
/// that *are* actually referenced. These get code generated when the module /// 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*> CFConstantStringMap;
llvm::StringMap<llvm::Constant*> ConstantStringMap; 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. /// before main.
std::vector<llvm::Constant*> CXXGlobalInits; 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 /// CFConstantStringClassRef - Cached reference to the class for constant
/// strings. This value has type int * but is actually an Obj-C class pointer. /// strings. This value has type int * but is actually an Obj-C class pointer.
llvm::Constant *CFConstantStringClassRef; llvm::Constant *CFConstantStringClassRef;
@ -343,14 +325,18 @@ public:
void AddAnnotation(llvm::Constant *C) { Annotations.push_back(C); } 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 /// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name. /// type and name.
llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty, llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty,
const char *Name); llvm::StringRef Name);
/// CreateRuntimeVariable - Create a new runtime global variable with the /// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name. /// specified type and name.
llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty, llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty,
const char *Name); llvm::StringRef Name);
void UpdateCompletedType(const TagDecl *TD) { void UpdateCompletedType(const TagDecl *TD) {
// Make sure that this type is translated. // Make sure that this type is translated.
@ -422,13 +408,14 @@ public:
AttributeListType &PAL, AttributeListType &PAL,
unsigned &CallingConv); unsigned &CallingConv);
const char *getMangledName(const GlobalDecl &D); void getMangledName(MangleBuffer &Buffer, GlobalDecl D);
void getMangledName(MangleBuffer &Buffer, const NamedDecl *ND);
const char *getMangledName(const NamedDecl *ND); void getMangledCXXCtorName(MangleBuffer &Buffer,
const char *getMangledCXXCtorName(const CXXConstructorDecl *D, const CXXConstructorDecl *D,
CXXCtorType Type); CXXCtorType Type);
const char *getMangledCXXDtorName(const CXXDestructorDecl *D, void getMangledCXXDtorName(MangleBuffer &Buffer,
CXXDtorType Type); const CXXDestructorDecl *D,
CXXDtorType Type);
void EmitTentativeDefinition(const VarDecl *D); void EmitTentativeDefinition(const VarDecl *D);
@ -456,14 +443,12 @@ public:
std::vector<const CXXRecordDecl*> DeferredVtables; std::vector<const CXXRecordDecl*> DeferredVtables;
private: private:
/// UniqueMangledName - Unique a name by (if necessary) inserting it into the llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref);
/// MangledNames string map.
const char *UniqueMangledName(const char *NameStart, const char *NameEnd);
llvm::Constant *GetOrCreateLLVMFunction(const char *MangledName, llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName,
const llvm::Type *Ty, const llvm::Type *Ty,
GlobalDecl D); GlobalDecl D);
llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName, llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
const llvm::PointerType *PTy, const llvm::PointerType *PTy,
const VarDecl *D); const VarDecl *D);
@ -492,7 +477,7 @@ private:
void EmitGlobalFunctionDefinition(GlobalDecl GD); void EmitGlobalFunctionDefinition(GlobalDecl GD);
void EmitGlobalVarDefinition(const VarDecl *D); void EmitGlobalVarDefinition(const VarDecl *D);
void EmitAliasDefinition(const ValueDecl *D); void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
// C++ related functions. // C++ related functions.
@ -519,9 +504,12 @@ private:
/// a C++ destructor Decl. /// a C++ destructor Decl.
void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); 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(); void EmitCXXGlobalInitFunc();
/// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals.
void EmitCXXGlobalDtorFunc();
void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D); void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D);
// FIXME: Hardcoding priority here is gross. // FIXME: Hardcoding priority here is gross.

View File

@ -469,8 +469,26 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
mangleName(Qualifier->getAsNamespace()); mangleName(Qualifier->getAsNamespace());
break; break;
case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpecWithTemplate: {
mangleType(QualType(Qualifier->getAsType(), 0)); 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; break;
case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Identifier:
// Member expressions can have these without prefixes. // Member expressions can have these without prefixes.
@ -1144,29 +1162,8 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
void CXXNameMangler::mangleType(const TypenameType *T) { void CXXNameMangler::mangleType(const TypenameType *T) {
// Typename types are always nested // Typename types are always nested
Out << 'N'; Out << 'N';
mangleUnresolvedScope(T->getQualifier());
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!");
mangleSourceName(T->getIdentifier()); mangleSourceName(T->getIdentifier());
Out << 'E'; Out << 'E';
} }

View File

@ -21,10 +21,8 @@
#include "CGCXX.h" #include "CGCXX.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
namespace llvm { #include "llvm/ADT/SmallString.h"
template<typename T> class SmallVectorImpl;
}
namespace clang { namespace clang {
class ASTContext; class ASTContext;
@ -37,6 +35,33 @@ namespace clang {
namespace CodeGen { namespace CodeGen {
class CovariantThunkAdjustment; class CovariantThunkAdjustment;
class ThunkAdjustment; 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 /// MangleContext - Context for tracking state which persists across multiple
/// calls to the C++ name mangler. /// calls to the C++ name mangler.

View File

@ -10,6 +10,7 @@
#include "clang/Driver/Arg.h" #include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h" #include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h" #include "clang/Driver/Option.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
using namespace clang::driver; 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 { void SeparateArg::render(const ArgList &Args, ArgStringList &Output) const {
if (getOption().hasForceJoinedRender()) { if (getOption().hasForceJoinedRender()) {
assert(getNumValues() == 1 && "Cannot force joined render with > 1 args."); assert(getNumValues() == 1 && "Cannot force joined render with > 1 args.");
// FIXME: Avoid std::string. Output.push_back(Args.MakeArgString(llvm::StringRef(getOption().getName()) +
std::string Joined(getOption().getName()); getValue(Args, 0)));
Joined += Args.getArgString(getIndex());
Output.push_back(Args.MakeArgString(Joined.c_str()));
} else { } else {
Output.push_back(Args.getArgString(getIndex())); Output.push_back(Args.getArgString(getIndex()));
for (unsigned i = 0; i < NumValues; ++i) 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() << '"'; OS << " \"" << C->getExecutable() << '"';
for (ArgStringList::const_iterator it = C->getArguments().begin(), for (ArgStringList::const_iterator it = C->getArguments().begin(),
ie = C->getArguments().end(); it != ie; ++it) { ie = C->getArguments().end(); it != ie; ++it) {
if (Quote) OS << ' ';
OS << " \"" << *it << '"'; if (!Quote) {
else OS << *it;
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; OS << Terminator;
} else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) { } 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); std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
Argv[C.getArguments().size() + 1] = 0; Argv[C.getArguments().size() + 1] = 0;
if (getDriver().CCCEcho || getArgs().hasArg(options::OPT_v)) if (getDriver().CCCEcho || getDriver().CCPrintOptions ||
PrintJob(llvm::errs(), C, "\n", false); 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; std::string Error;
int Res = int Res =

View File

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

View File

@ -167,11 +167,13 @@ Option *OptTable::CreateOption(unsigned id) const {
if (info.Flags & RenderAsInput) if (info.Flags & RenderAsInput)
Opt->setNoOptAsInput(true); Opt->setNoOptAsInput(true);
if (info.Flags & RenderJoined) { 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); Opt->setForceJoinedRender(true);
} }
if (info.Flags & RenderSeparate) { 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); Opt->setForceSeparateRender(true);
} }
if (info.Flags & Unsupported) if (info.Flags & Unsupported)

View File

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

View File

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

View File

@ -655,6 +655,12 @@ static std::string getEffectiveClangTriple(const Driver &D,
} else { } else {
const toolchains::Darwin &DarwinTC( const toolchains::Darwin &DarwinTC(
reinterpret_cast<const toolchains::Darwin&>(TC)); 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]; unsigned Version[3];
DarwinTC.getTargetVersion(Version); DarwinTC.getTargetVersion(Version);
@ -686,6 +692,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs, const InputInfoList &Inputs,
const ArgList &Args, const ArgList &Args,
const char *LinkingOutput) const { const char *LinkingOutput) const {
bool KernelOrKext = Args.hasArg(options::OPT_mkernel,
options::OPT_fapple_kext);
const Driver &D = getToolChain().getDriver(); const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs; ArgStringList CmdArgs;
@ -870,7 +878,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasFlag(options::OPT_fasynchronous_unwind_tables, Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
options::OPT_fno_asynchronous_unwind_tables, options::OPT_fno_asynchronous_unwind_tables,
getToolChain().IsUnwindTablesDefault() && getToolChain().IsUnwindTablesDefault() &&
!Args.hasArg(options::OPT_mkernel)); !KernelOrKext);
if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
AsynchronousUnwindTables)) AsynchronousUnwindTables))
CmdArgs.push_back("-munwind-tables"); CmdArgs.push_back("-munwind-tables");
@ -1029,12 +1037,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args)); 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. // Forward -f (flag) options which we can pass directly.
Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior); Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior);
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); 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_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_caret_diagnostics);
Args.AddLastArg(CmdArgs, options::OPT_fno_show_column); Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only); Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only);
@ -1080,6 +1098,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks"); 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. // -fexceptions=0 is default.
if (needsExceptions(Args, InputType, getToolChain().getTriple())) if (needsExceptions(Args, InputType, getToolChain().getTriple()))
CmdArgs.push_back("-fexceptions"); CmdArgs.push_back("-fexceptions");
@ -1088,7 +1112,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fsjlj-exceptions"); CmdArgs.push_back("-fsjlj-exceptions");
// -frtti is default. // -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"); CmdArgs.push_back("-fno-rtti");
// -fsigned-char is default. // -fsigned-char is default.
@ -1101,6 +1126,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_threadsafe_statics)) options::OPT_fno_threadsafe_statics))
CmdArgs.push_back("-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. // -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
getToolChain().getTriple().getOS() == llvm::Triple::Win32)) getToolChain().getTriple().getOS() == llvm::Triple::Win32))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,6 +21,7 @@
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h" #include "clang/AST/TypeLocVisitor.h"
#include "clang/Lex/MacroInfo.h" #include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h" #include "clang/Basic/FileManager.h"
@ -563,9 +564,10 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SOURCE_LOCATION_PRELOADS); RECORD(SOURCE_LOCATION_PRELOADS);
RECORD(STAT_CACHE); RECORD(STAT_CACHE);
RECORD(EXT_VECTOR_DECLS); RECORD(EXT_VECTOR_DECLS);
RECORD(COMMENT_RANGES);
RECORD(VERSION_CONTROL_BRANCH_REVISION); RECORD(VERSION_CONTROL_BRANCH_REVISION);
RECORD(UNUSED_STATIC_FUNCS);
RECORD(MACRO_DEFINITION_OFFSETS);
// SourceManager Block. // SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK); BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY); RECORD(SM_SLOC_FILE_ENTRY);
@ -573,14 +575,15 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SM_SLOC_BUFFER_BLOB); RECORD(SM_SLOC_BUFFER_BLOB);
RECORD(SM_SLOC_INSTANTIATION_ENTRY); RECORD(SM_SLOC_INSTANTIATION_ENTRY);
RECORD(SM_LINE_TABLE); RECORD(SM_LINE_TABLE);
RECORD(SM_HEADER_FILE_INFO);
// Preprocessor Block. // Preprocessor Block.
BLOCK(PREPROCESSOR_BLOCK); BLOCK(PREPROCESSOR_BLOCK);
RECORD(PP_MACRO_OBJECT_LIKE); RECORD(PP_MACRO_OBJECT_LIKE);
RECORD(PP_MACRO_FUNCTION_LIKE); RECORD(PP_MACRO_FUNCTION_LIKE);
RECORD(PP_TOKEN); RECORD(PP_TOKEN);
RECORD(PP_MACRO_INSTANTIATION);
RECORD(PP_MACRO_DEFINITION);
// Decls and Types block. // Decls and Types block.
BLOCK(DECLTYPES_BLOCK); BLOCK(DECLTYPES_BLOCK);
RECORD(TYPE_EXT_QUAL); 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::VBR, 8)); // Include location
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives 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 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
return Stream.EmitAbbrev(Abbrev); return Stream.EmitAbbrev(Abbrev);
} }
@ -1019,20 +1027,6 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Stream.EmitRecord(pch::SM_LINE_TABLE, Record); 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 // Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry. // entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets; std::vector<uint32_t> SLocEntryOffsets;
@ -1069,6 +1063,16 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// The source location entry is a file. The blob associated // The source location entry is a file. The blob associated
// with this entry is the file name. // 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. // Turn the file name into an absolute path, if it isn't already.
const char *Filename = Content->Entry->getName(); const char *Filename = Content->Entry->getName();
llvm::sys::Path FilePath(Filename, strlen(Filename)); 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, // Loop over all the macro definitions that are live at the end of the file,
// emitting each to the PP section. // emitting each to the PP section.
PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
I != E; ++I) { I != E; ++I) {
// FIXME: This emits macros in hash table order, we should do it in a stable // 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) I != E; ++I)
AddIdentifierRef(*I, Record); 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); Stream.EmitRecord(Code, Record);
Record.clear(); Record.clear();
@ -1230,25 +1241,68 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
} }
++NumMacros; ++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(); Stream.ExitBlock();
}
// Write the offsets table for the preprocessing record.
void PCHWriter::WriteComments(ASTContext &Context) { if (NumPreprocessingRecords > 0) {
using namespace llvm; // Write the offsets table for identifier IDs.
using namespace llvm;
if (Context.Comments.empty()) BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
return; Abbrev->Add(BitCodeAbbrevOp(pch::MACRO_DEFINITION_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records
BitCodeAbbrev *CommentAbbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs
CommentAbbrev->Add(BitCodeAbbrevOp(pch::COMMENT_RANGES)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
CommentAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
unsigned CommentCode = Stream.EmitAbbrev(CommentAbbrev);
Record.clear();
RecordData Record; Record.push_back(pch::MACRO_DEFINITION_OFFSETS);
Record.push_back(pch::COMMENT_RANGES); Record.push_back(NumPreprocessingRecords);
Stream.EmitRecordWithBlob(CommentCode, Record, Record.push_back(MacroDefinitionOffsets.size());
(const char*)&Context.Comments[0], Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record,
Context.Comments.size() * sizeof(SourceRange)); (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. // Write the remaining PCH contents.
RecordData Record; RecordData Record;
Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4); Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5);
WriteMetadata(Context, isysroot); WriteMetadata(Context, isysroot);
WriteLanguageOptions(Context.getLangOptions()); WriteLanguageOptions(Context.getLangOptions());
if (StatCalls && !isysroot) if (StatCalls && !isysroot)
WriteStatCache(*StatCalls, isysroot); WriteStatCache(*StatCalls, isysroot);
WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
WriteComments(Context);
// Write the record of special types. // Write the record of special types.
Record.clear(); Record.clear();
@ -2149,6 +2202,16 @@ pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID; 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) { void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
if (SelRef.getAsOpaquePtr() == 0) { if (SelRef.getAsOpaquePtr() == 0) {
Record.push_back(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) { static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
// -dM mode just scans and ignores all tokens in the files, then dumps out // -dM mode just scans and ignores all tokens in the files, then dumps out
// the macro table at the end. // the macro table at the end.
PP.EnterMainSourceFile(); if (PP.EnterMainSourceFile())
return;
Token Tok; Token Tok;
do PP.Lex(Tok); do PP.Lex(Tok);
@ -495,7 +496,8 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
PP.addPPCallbacks(Callbacks); PP.addPPCallbacks(Callbacks);
// After we have configured the preprocessor, enter the main file. // 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 // 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 // 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. // Get the first preprocessing token.
PP.EnterMainSourceFile(); if (PP.EnterMainSourceFile())
return;
Token PPTok; Token PPTok;
PP.Lex(PPTok); PP.Lex(PPTok);

View File

@ -31,7 +31,7 @@
#include <algorithm> #include <algorithm>
using namespace clang; using namespace clang;
bool clang::ProcessWarningOptions(Diagnostic &Diags, void clang::ProcessWarningOptions(Diagnostic &Diags,
const DiagnosticOptions &Opts) { const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
@ -122,6 +122,4 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
if (Diags.setDiagnosticGroupMapping(OptStart, Mapping)) if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt); 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 double __m128d __attribute__((__vector_size__(16)));
typedef long long __m128i __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 short __v8hi __attribute__((__vector_size__(16)));
typedef char __v16qi __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. */ /* SSE4 Multiple Packed Sums of Absolute Difference. */
#define _mm_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw128((X), (Y), (M)) #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 /* __SSE4_1__ */
#endif /* _SMMINTRIN_H */ #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> #include <mmintrin.h>
typedef int __v4si __attribute__((__vector_size__(16)));
typedef float __v4sf __attribute__((__vector_size__(16))); typedef float __v4sf __attribute__((__vector_size__(16)));
typedef float __m128 __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__)) static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_and_ps(__m128 a, __m128 b) _mm_and_ps(__m128 a, __m128 b)
{ {
typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)((__v4si)a & (__v4si)b); return (__m128)((__v4si)a & (__v4si)b);
} }
static inline __m128 __attribute__((__always_inline__, __nodebug__)) static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_andnot_ps(__m128 a, __m128 b) _mm_andnot_ps(__m128 a, __m128 b)
{ {
typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)(~(__v4si)a & (__v4si)b); return (__m128)(~(__v4si)a & (__v4si)b);
} }
static inline __m128 __attribute__((__always_inline__, __nodebug__)) static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_or_ps(__m128 a, __m128 b) _mm_or_ps(__m128 a, __m128 b)
{ {
typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)((__v4si)a | (__v4si)b); return (__m128)((__v4si)a | (__v4si)b);
} }
static inline __m128 __attribute__((__always_inline__, __nodebug__)) static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_xor_ps(__m128 a, __m128 b) _mm_xor_ps(__m128 a, __m128 b)
{ {
typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)((__v4si)a ^ (__v4si)b); return (__m128)((__v4si)a ^ (__v4si)b);
} }

View File

@ -16,6 +16,7 @@ add_clang_library(clangLex
PPMacroExpansion.cpp PPMacroExpansion.cpp
PTHLexer.cpp PTHLexer.cpp
Pragma.cpp Pragma.cpp
PreprocessingRecord.cpp
Preprocessor.cpp Preprocessor.cpp
PreprocessorLexer.cpp PreprocessorLexer.cpp
ScratchBuffer.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 // If this BCPL-style comment is in a macro definition, transmogrify it into
// a C-style block comment. // 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?"); assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?");
Spelling[1] = '*'; // Change prefix to "/*". Spelling[1] = '*'; // Change prefix to "/*".
Spelling += "*/"; // add suffix. Spelling += "*/"; // add suffix.

View File

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

View File

@ -71,7 +71,11 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
IdentifierInfo *II = MacroNameTok.getIdentifierInfo(); IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
if (II == 0) { 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); const IdentifierInfo &Info = Identifiers.get(Spelling);
if (Info.isCPlusPlusOperatorKeyword()) if (Info.isCPlusPlusOperatorKeyword())
// C++ 2.5p2: Alternative tokens behave the same as its primary token // 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 // 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 // allows us to avoid looking up the identifier info for #define/#undef and
// other common directives. // 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]; char FirstChar = RawCharData[0];
if (FirstChar >= 'a' && FirstChar <= 'z' && if (FirstChar >= 'a' && FirstChar <= 'z' &&
FirstChar != 'i' && FirstChar != 'e') { FirstChar != 'i' && FirstChar != 'e') {
@ -614,8 +623,11 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
llvm::SmallString<64> IntegerBuffer; llvm::SmallString<64> IntegerBuffer;
IntegerBuffer.resize(DigitTok.getLength()); IntegerBuffer.resize(DigitTok.getLength());
const char *DigitTokBegin = &IntegerBuffer[0]; 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 // 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 // is always a simple digit string computed in decimal, so we do this manually
// here. // here.
@ -900,8 +912,12 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
// Verify that there is nothing after the string, other than EOM. // Verify that there is nothing after the string, other than EOM.
CheckEndOfDirective("ident"); CheckEndOfDirective("ident");
if (Callbacks) if (Callbacks) {
Callbacks->Ident(Tok.getLocation(), getSpelling(StrTok)); 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. // Get the MemoryBuffer for this FID, if it fails, we fail.
const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID); bool Invalid = false;
if (!InputFile) const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID,
&Invalid);
if (Invalid)
return true; return true;
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);

View File

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