aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--VER2
-rw-r--r--docs/Block-ABI-Apple.txt669
-rw-r--r--docs/LanguageExtensions.html2
-rw-r--r--docs/UsersManual.html7
-rw-r--r--include/clang-c/Index.h18
-rw-r--r--include/clang/AST/ASTContext.h33
-rw-r--r--include/clang/AST/Expr.h2
-rw-r--r--include/clang/AST/ExternalASTSource.h8
-rw-r--r--include/clang/AST/Stmt.h4
-rw-r--r--include/clang/AST/UnresolvedSet.h1
-rw-r--r--include/clang/Basic/BuiltinsX86.def24
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td8
-rw-r--r--include/clang/Basic/DiagnosticGroups.td2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td27
-rw-r--r--include/clang/Basic/SourceLocation.h14
-rw-r--r--include/clang/Basic/SourceManager.h17
-rw-r--r--include/clang/Basic/Version.h2
-rw-r--r--include/clang/Checker/BugReporter/BugReporter.h26
-rw-r--r--include/clang/Checker/PathSensitive/GRState.h1
-rw-r--r--include/clang/Checker/PathSensitive/Store.h1
-rw-r--r--include/clang/CodeGen/CodeGenOptions.h8
-rw-r--r--include/clang/Driver/CC1Options.td14
-rw-r--r--include/clang/Driver/Driver.h7
-rw-r--r--include/clang/Driver/Options.td8
-rw-r--r--include/clang/Frontend/ASTUnit.h24
-rw-r--r--include/clang/Frontend/CompilerInstance.h1
-rw-r--r--include/clang/Frontend/FrontendActions.h16
-rw-r--r--include/clang/Frontend/FrontendOptions.h5
-rw-r--r--include/clang/Frontend/PCHBitCodes.h23
-rw-r--r--include/clang/Frontend/PCHReader.h53
-rw-r--r--include/clang/Frontend/PCHWriter.h17
-rw-r--r--include/clang/Frontend/PreprocessorOptions.h6
-rw-r--r--include/clang/Frontend/Utils.h2
-rw-r--r--include/clang/Frontend/VerifyDiagnosticsClient.h1
-rw-r--r--include/clang/Lex/HeaderSearch.h7
-rw-r--r--include/clang/Lex/PreprocessingRecord.h274
-rw-r--r--include/clang/Lex/Preprocessor.h22
-rw-r--r--include/clang/Parse/Action.h12
-rw-r--r--include/clang/Parse/Parser.h1
-rw-r--r--lib/AST/ASTContext.cpp264
-rw-r--r--lib/AST/Decl.cpp5
-rw-r--r--lib/AST/DeclObjC.cpp5
-rw-r--r--lib/AST/Expr.cpp15
-rw-r--r--lib/AST/ExprConstant.cpp27
-rw-r--r--lib/AST/TypePrinter.cpp31
-rw-r--r--lib/Basic/SourceLocation.cpp28
-rw-r--r--lib/Basic/SourceManager.cpp76
-rw-r--r--lib/Checker/BasicStore.cpp5
-rw-r--r--lib/Checker/BugReporter.cpp19
-rw-r--r--lib/Checker/BugReporterVisitors.cpp67
-rw-r--r--lib/Checker/CallAndMessageChecker.cpp195
-rw-r--r--lib/Checker/CheckDeadStores.cpp25
-rw-r--r--lib/Checker/FlatStore.cpp4
-rw-r--r--lib/Checker/GRExprEngine.cpp4
-rw-r--r--lib/Checker/GRState.cpp3
-rw-r--r--lib/Checker/RegionStore.cpp22
-rw-r--r--lib/CodeGen/CGBuiltin.cpp76
-rw-r--r--lib/CodeGen/CGCXX.cpp55
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp20
-rw-r--r--lib/CodeGen/CGDecl.cpp15
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp48
-rw-r--r--lib/CodeGen/CGException.cpp34
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp2
-rw-r--r--lib/CodeGen/CGVtable.cpp108
-rw-r--r--lib/CodeGen/CodeGenFunction.h6
-rw-r--r--lib/CodeGen/CodeGenModule.cpp159
-rw-r--r--lib/CodeGen/CodeGenModule.h72
-rw-r--r--lib/CodeGen/Mangle.cpp45
-rw-r--r--lib/CodeGen/Mangle.h33
-rw-r--r--lib/Driver/Arg.cpp9
-rw-r--r--lib/Driver/Compilation.cpp49
-rw-r--r--lib/Driver/Driver.cpp8
-rw-r--r--lib/Driver/OptTable.cpp6
-rw-r--r--lib/Driver/ToolChains.cpp4
-rw-r--r--lib/Driver/ToolChains.h2
-rw-r--r--lib/Driver/Tools.cpp38
-rw-r--r--lib/Frontend/ASTUnit.cpp4
-rw-r--r--lib/Frontend/CacheTokens.cpp16
-rw-r--r--lib/Frontend/CompilerInstance.cpp33
-rw-r--r--lib/Frontend/CompilerInvocation.cpp19
-rw-r--r--lib/Frontend/FrontendActions.cpp24
-rw-r--r--lib/Frontend/PCHReader.cpp286
-rw-r--r--lib/Frontend/PCHWriter.cpp139
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp6
-rw-r--r--lib/Frontend/RewriteMacros.cpp3
-rw-r--r--lib/Frontend/Warnings.cpp4
-rw-r--r--lib/Headers/emmintrin.h1
-rw-r--r--lib/Headers/nmmintrin.h35
-rw-r--r--lib/Headers/smmintrin.h112
-rw-r--r--lib/Headers/varargs.h26
-rw-r--r--lib/Headers/xmmintrin.h5
-rw-r--r--lib/Lex/CMakeLists.txt1
-rw-r--r--lib/Lex/Lexer.cpp6
-rw-r--r--lib/Lex/MacroArgs.cpp31
-rw-r--r--lib/Lex/PPDirectives.cpp28
-rw-r--r--lib/Lex/PPLexerChange.cpp6
-rw-r--r--lib/Lex/PPMacroExpansion.cpp8
-rw-r--r--lib/Lex/Pragma.cpp5
-rw-r--r--lib/Lex/PreprocessingRecord.cpp128
-rw-r--r--lib/Lex/Preprocessor.cpp30
-rw-r--r--lib/Lex/TokenLexer.cpp11
-rw-r--r--lib/Parse/AttributeList.cpp2
-rw-r--r--lib/Parse/ParseDecl.cpp2
-rw-r--r--lib/Parse/ParseDeclCXX.cpp12
-rw-r--r--lib/Parse/Parser.cpp18
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp369
-rw-r--r--lib/Sema/AnalysisBasedWarnings.h35
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/CXXFieldCollector.h5
-rw-r--r--lib/Sema/ParseAST.cpp3
-rw-r--r--lib/Sema/Sema.cpp5
-rw-r--r--lib/Sema/Sema.h66
-rw-r--r--lib/Sema/SemaAccess.cpp290
-rw-r--r--lib/Sema/SemaChecking.cpp279
-rw-r--r--lib/Sema/SemaCodeComplete.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp129
-rw-r--r--lib/Sema/SemaDeclCXX.cpp59
-rw-r--r--lib/Sema/SemaExpr.cpp42
-rw-r--r--lib/Sema/SemaExprCXX.cpp36
-rw-r--r--lib/Sema/SemaInit.cpp96
-rw-r--r--lib/Sema/SemaInit.h7
-rw-r--r--lib/Sema/SemaLookup.cpp2
-rw-r--r--lib/Sema/SemaObjCProperty.cpp14
-rw-r--r--lib/Sema/SemaOverload.cpp186
-rw-r--r--lib/Sema/SemaOverload.h14
-rw-r--r--test/Analysis/dead-stores.c33
-rw-r--r--test/Analysis/misc-ps-region-store.m22
-rw-r--r--test/Analysis/uninit-vals-ps-region.m (renamed from test/Analysis/uninit-vals-ps-region.c)15
-rw-r--r--test/CXX/class.access/class.access.nest/p1.cpp33
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp34
-rw-r--r--test/CXX/class.access/p4.cpp58
-rw-r--r--test/CXX/class/class.union/p1.cpp14
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p1.cpp33
-rw-r--r--test/CodeGen/atomic.c1
-rw-r--r--test/CodeGen/const-arithmetic.c8
-rw-r--r--test/CodeGenCXX/attr.cpp8
-rw-r--r--test/CodeGenCXX/cxx-apple-kext.cpp36
-rw-r--r--test/CodeGenCXX/deferred-global-init.cpp2
-rw-r--r--test/CodeGenCXX/global-dtor-no-atexit.cpp14
-rw-r--r--test/CodeGenCXX/global-init.cpp2
-rw-r--r--test/CodeGenCXX/mangle.cpp15
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp4
-rw-r--r--test/Driver/cc-print-options.c7
-rw-r--r--test/Driver/darwin-ld.c4
-rw-r--r--test/Index/annotate-tokens-pp.c58
-rw-r--r--test/Index/c-index-getCursor-pp.c18
-rw-r--r--test/Index/c-index-getCursor-test.m13
-rw-r--r--test/PCH/changed-files.c31
-rw-r--r--test/PCH/headermap.h3
-rw-r--r--test/PCH/headermap.m15
-rw-r--r--test/Sema/block-byref-args.c22
-rw-r--r--test/Sema/block-misc.c2
-rw-r--r--test/Sema/invalid-init-diag.c2
-rw-r--r--test/Sema/warn-shadow.c45
-rw-r--r--test/Sema/x86-intrinsics-headers.c8
-rw-r--r--test/SemaCXX/access-base-class.cpp5
-rw-r--r--test/SemaCXX/class.cpp18
-rw-r--r--test/SemaCXX/condition.cpp2
-rw-r--r--test/SemaCXX/conditional-expr.cpp6
-rw-r--r--test/SemaCXX/warn-shadow.cpp44
-rw-r--r--test/SemaCXX/warn-sign-compare.cpp72
-rw-r--r--test/SemaObjC/block-type-safety.m96
-rw-r--r--test/SemaObjC/class-method-self.m4
-rw-r--r--test/SemaObjC/comptypes-1.m6
-rw-r--r--test/SemaObjC/id.m3
-rw-r--r--test/SemaObjC/invalid-code.m7
-rw-r--r--test/SemaObjC/ivar-in-class-extension.m4
-rw-r--r--test/SemaObjC/property-not-lvalue.m6
-rw-r--r--test/SemaObjC/warn-incompatible-builtin-types.m42
-rw-r--r--test/lit.cfg5
-rw-r--r--tools/CIndex/CIndex.cpp265
-rw-r--r--tools/CIndex/CIndex.exports1
-rw-r--r--tools/CIndex/CIndexUSRs.cpp26
-rw-r--r--tools/CIndex/CXCursor.cpp44
-rw-r--r--tools/CIndex/CXCursor.h22
-rw-r--r--tools/driver/cc1_main.cpp1
-rw-r--r--tools/driver/driver.cpp5
-rw-r--r--www/cxx_compatibility.html244
181 files changed, 5349 insertions, 1744 deletions
diff --git a/Makefile b/Makefile
index 481dd389aabe..f7e9e85bce83 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ $(RecursiveTargets)::
endif
test::
- @ $(MAKE) -C test
+ @ $(MAKE) -C test
report::
@ $(MAKE) -C test report
@@ -27,7 +27,8 @@ clean::
@ $(MAKE) -C test clean
tags::
- $(Verb) etags `find . -type f -name \*.h | grep -v /lib/Headers | grep -v /test/` `find . -type f -name \*.cpp | grep -v /lib/Headers | grep -v /test/`
+ $(Verb) etags `find . -type f -name '*.h' -or -name '*.cpp' | \
+ grep -v /lib/Headers | grep -v /test/`
cscope.files:
find tools lib include -name '*.cpp' \
diff --git a/VER b/VER
index 9459d4ba2a0d..c239c60cba28 100644
--- a/VER
+++ b/VER
@@ -1 +1 @@
-1.1
+1.5
diff --git a/docs/Block-ABI-Apple.txt b/docs/Block-ABI-Apple.txt
new file mode 100644
index 000000000000..6fb75da40490
--- /dev/null
+++ b/docs/Block-ABI-Apple.txt
@@ -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);
+
+
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index d32842b5d23d..fe364ef9c00a 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -315,7 +315,7 @@ enabled. clang does not yet fully implement this feature.</p>
<p>The syntax and high level language feature description is in <a
href="BlockLanguageSpec.txt">BlockLanguageSpec.txt</a>. Implementation and ABI
details for the clang implementation are in <a
-href="BlockImplementation.txt">BlockImplementation.txt</a>.</p>
+href="Block-ABI-Apple.txt">Block-ABI-Apple.txt</a>.</p>
<p>Query for this feature with __has_feature(blocks).</p>
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 41715bb2ac65..e7ea133ce91a 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -796,6 +796,13 @@ ask on the mailing list about how you can help.</p>
<p>Note that released Clang compilers will refuse to even try to use clang to compile C++ code unless you pass the <tt>-ccc-clang-cxx</tt> option to the driver. To turn on Clang's C++ support, please pass that flag. Clang compilers built from the Subversion trunk enable C++ support by default, and do not require the <tt>-ccc-clang-cxx</tt> flag.</p>
+<p>Clang strives to strictly conform to the C++ standard. That means
+it will reject invalid C++ code that another compiler may accept. If
+Clang reports errors in your code, please check
+the <a href="http://clang.llvm.org/cxx_compatibility.html">C++
+Compatibility</a> page to see whether they are C++-conformance bugs
+and how you can fix them.</p>
+
<!-- ======================================================================= -->
<h2 id="objcxx">Objective C++ Language Features</h2>
<!-- ======================================================================= -->
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 15afe8f50376..6120c4863fd7 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -728,7 +728,8 @@ enum CXCursorKind {
CXCursor_InvalidFile = 70,
CXCursor_NoDeclFound = 71,
CXCursor_NotImplemented = 72,
- CXCursor_LastInvalid = 72,
+ CXCursor_InvalidCode = 73,
+ CXCursor_LastInvalid = CXCursor_InvalidCode,
/* Expressions */
CXCursor_FirstExpr = 100,
@@ -796,7 +797,14 @@ enum CXCursorKind {
CXCursor_IBActionAttr = 401,
CXCursor_IBOutletAttr = 402,
- CXCursor_LastAttr = CXCursor_IBOutletAttr
+ CXCursor_LastAttr = CXCursor_IBOutletAttr,
+
+ /* Preprocessing */
+ CXCursor_PreprocessingDirective = 500,
+ CXCursor_MacroDefinition = 501,
+ CXCursor_MacroInstantiation = 502,
+ CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective,
+ CXCursor_LastPreprocessing = CXCursor_MacroInstantiation
};
/**
@@ -889,6 +897,12 @@ CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind);
CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind);
/***
+ * \brief Determine whether the given cursor represents a preprocessing
+ * element, such as a preprocessor directive or macro instantiation.
+ */
+CINDEX_LINKAGE unsigned clang_isPreprocessing(enum CXCursorKind);
+
+/***
* \brief Determine whether the given cursor represents a currently
* unexposed piece of the AST (e.g., CXCursor_UnexposedStmt).
*/
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index d12a182078e4..e77dcf86cca6 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -259,19 +259,11 @@ class ASTContext {
/// this ASTContext object.
LangOptions LangOpts;
- /// \brief Whether we have already loaded comment source ranges from an
- /// external source.
- bool LoadedExternalComments;
-
/// MallocAlloc/BumpAlloc - The allocator objects used to create AST objects.
bool FreeMemory;
llvm::MallocAllocator MallocAlloc;
llvm::BumpPtrAllocator BumpAlloc;
- /// \brief Mapping from declarations to their comments, once we have
- /// already looked up the comment associated with a given declaration.
- llvm::DenseMap<const Decl *, std::string> DeclComments;
-
public:
const TargetInfo &Target;
IdentifierTable &Idents;
@@ -287,10 +279,6 @@ public:
QualType ObjCClassRedefinitionType;
QualType ObjCSelRedefinitionType;
- /// \brief Source ranges for all of the comments in the source file,
- /// sorted in order of appearance in the translation unit.
- std::vector<SourceRange> Comments;
-
SourceManager& getSourceManager() { return SourceMgr; }
const SourceManager& getSourceManager() const { return SourceMgr; }
void *Allocate(unsigned Size, unsigned Align = 8) {
@@ -357,8 +345,6 @@ public:
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
- const char *getCommentForDecl(const Decl *D);
-
// Builtin Types.
CanQualType VoidTy;
CanQualType BoolTy;
@@ -1161,6 +1147,8 @@ public:
/// Compatibility predicates used to check assignment expressions.
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
+ bool typesAreBlockPointerCompatible(QualType, QualType);
+
bool isObjCIdType(QualType T) const {
return T == ObjCIdTypedefType;
}
@@ -1179,13 +1167,16 @@ public:
const ObjCObjectPointerType *RHSOPT);
bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
const ObjCInterfaceType *RHS);
+ bool canAssignObjCInterfacesInBlockPointer(
+ const ObjCObjectPointerType *LHSOPT,
+ const ObjCObjectPointerType *RHSOPT);
bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
QualType areCommonBaseCompatible(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT);
// Functions for calculating composite types
- QualType mergeTypes(QualType, QualType);
- QualType mergeFunctionTypes(QualType, QualType);
+ QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false);
+ QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false);
/// UsualArithmeticConversionsType - handles the various conversions
/// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9)
@@ -1312,10 +1303,10 @@ static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
/// this ever changes, this operator will have to be changed, too.)
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
/// @code
-/// // Default alignment (16)
+/// // Default alignment (8)
/// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments);
/// // Specific alignment
-/// IntegerLiteral *Ex2 = new (Context, 8) IntegerLiteral(arguments);
+/// IntegerLiteral *Ex2 = new (Context, 4) IntegerLiteral(arguments);
/// @endcode
/// Please note that you cannot use delete on the pointer; it must be
/// deallocated using an explicit destructor call followed by
@@ -1346,10 +1337,10 @@ inline void operator delete(void *Ptr, clang::ASTContext &C, size_t)
/// null on error.
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
/// @code
-/// // Default alignment (16)
+/// // Default alignment (8)
/// char *data = new (Context) char[10];
/// // Specific alignment
-/// char *data = new (Context, 8) char[10];
+/// char *data = new (Context, 4) char[10];
/// @endcode
/// Please note that you cannot use delete on the pointer; it must be
/// deallocated using an explicit destructor call followed by
@@ -1361,7 +1352,7 @@ inline void operator delete(void *Ptr, clang::ASTContext &C, size_t)
/// allocator supports it).
/// @return The allocated memory. Could be NULL.
inline void *operator new[](size_t Bytes, clang::ASTContext& C,
- size_t Alignment = 16) throw () {
+ size_t Alignment = 8) throw () {
return C.Allocate(Bytes, Alignment);
}
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 23076b93e13b..6b14e47cbef5 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -150,7 +150,6 @@ public:
LV_InvalidExpression,
LV_MemberFunction,
LV_SubObjCPropertySetting,
- LV_SubObjCPropertyGetterSetting,
LV_ClassTemporary
};
isLvalueResult isLvalue(ASTContext &Ctx) const;
@@ -182,7 +181,6 @@ public:
MLV_NoSetterProperty,
MLV_MemberFunction,
MLV_SubObjCPropertySetting,
- MLV_SubObjCPropertyGetterSetting,
MLV_ClassTemporary
};
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 0670d1a62094..b8d80bc8978d 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -58,14 +58,6 @@ public:
virtual ~ExternalASTSource();
- /// \brief Reads the source ranges that correspond to comments from
- /// an external AST source.
- ///
- /// \param Comments the contents of this vector will be
- /// replaced with the sorted set of source ranges corresponding to
- /// comments in the source code.
- virtual void ReadComments(std::vector<SourceRange> &Comments) = 0;
-
/// \brief Resolve a type ID into a type, potentially building a new
/// type.
virtual QualType GetType(uint32_t ID) = 0;
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 94caa6faad66..466848976cb3 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -126,12 +126,12 @@ public:
// Only allow allocation of Stmts using the allocator in ASTContext
// or by doing a placement new.
void* operator new(size_t bytes, ASTContext& C,
- unsigned alignment = 16) throw() {
+ unsigned alignment = 8) throw() {
return ::operator new(bytes, C, alignment);
}
void* operator new(size_t bytes, ASTContext* C,
- unsigned alignment = 16) throw() {
+ unsigned alignment = 8) throw() {
return ::operator new(bytes, *C, alignment);
}
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index 9c59229e3134..553f04d76aec 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -94,6 +94,7 @@ public:
NamedDecl *getDecl() const { return ir->getDecl(); }
AccessSpecifier getAccess() const { return ir->getAccess(); }
+ DeclAccessPair getPair() const { return *ir; }
NamedDecl *operator*() const { return getDecl(); }
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 9a79f90d1e52..00b076aa1004 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -293,4 +293,28 @@ BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_pcmpeqq, "V2LLiV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16ci", "")
+// SSE 4.2
+BUILTIN(__builtin_ia32_pcmpistrm128, "V16cV16cV16cc", "")
+BUILTIN(__builtin_ia32_pcmpistri128, "iV16cV16cc", "")
+BUILTIN(__builtin_ia32_pcmpestrm128, "V16cV16ciV16cic", "")
+BUILTIN(__builtin_ia32_pcmpestri128, "iV16ciV16cic","")
+
+BUILTIN(__builtin_ia32_pcmpistria128, "iV16ciV16cic","")
+BUILTIN(__builtin_ia32_pcmpistric128, "iV16ciV16cic","")
+BUILTIN(__builtin_ia32_pcmpistrio128, "iV16ciV16cic","")
+BUILTIN(__builtin_ia32_pcmpistris128, "iV16ciV16cic","")
+BUILTIN(__builtin_ia32_pcmpistriz128, "iV16ciV16cic","")
+
+BUILTIN(__builtin_ia32_pcmpestria128, "iV16ciV16cic","")
+BUILTIN(__builtin_ia32_pcmpestric128, "iV16ciV16cic","")
+BUILTIN(__builtin_ia32_pcmpestrio128, "iV16ciV16cic","")
+BUILTIN(__builtin_ia32_pcmpestris128, "iV16ciV16cic","")
+BUILTIN(__builtin_ia32_pcmpestriz128, "iV16ciV16cic","")
+
+BUILTIN(__builtin_ia32_pcmpgtq, "V2LLiV2LLiV2LLi", "")
+
+BUILTIN(__builtin_ia32_crc32qi, "iic", "")
+BUILTIN(__builtin_ia32_crc32hi, "iis", "")
+BUILTIN(__builtin_ia32_crc32si, "iii", "")
+BUILTIN(__builtin_ia32_crc32di, "LLiLLiLLi", "")
#undef BUILTIN
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 849e6437fbe6..8e791c3422fc 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -65,9 +65,6 @@ def err_target_invalid_feature : Error<"invalid target feature '%0'">;
// Source manager
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
-def err_file_size_changed : Error<
- "size of file '%0' changed since it was first processed (from %1 to %2)">,
- DefaultFatal;
def err_file_modified : Error<
"file '%0' modified since it was first processed">, DefaultFatal;
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 2bce12db535b..3dbe47f4cf54 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -64,6 +64,8 @@ def err_drv_invalid_remap_file : Error<
"invalid option '%0' not of the form <from-file>;<to-file>">;
def err_drv_invalid_gcc_output_type : Error<
"invalid output type '%0' for use with gcc tool">;
+def err_drv_cc_print_options_failure : Error<
+ "unable to open CC_PRINT_OPTIONS file: %0">;
def warn_drv_input_file_unused : Warning<
"%0: '%1' input unused when '%2' is present">;
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index b77614bbefc0..3a28282d5522 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -51,12 +51,16 @@ def err_fe_unable_to_read_pch_file : Error<
"unable to read PCH file: '%0'">;
def err_fe_not_a_pch_file : Error<
"input is not a PCH file: '%0'">;
+def err_fe_pch_malformed : Error<
+ "malformed or corrupted PCH file: '%0'">, DefaultFatal;
def err_fe_pch_malformed_block : Error<
- "malformed block record in PCH file: '%0'">;
+ "malformed block record in PCH file: '%0'">, DefaultFatal;
def err_fe_pch_error_at_end_block : Error<
- "error at end of module block in PCH file: '%0'">;
+ "error at end of module block in PCH file: '%0'">, DefaultFatal;
def err_fe_unable_to_open_output : Error<
"unable to open output file '%0': '%1'">;
+def err_fe_unable_to_open_logfile : Error<
+ "unable to open logfile file '%0': '%1'">;
def err_fe_pth_file_has_no_source_header : Error<
"PTH file '%0' does not designate an original source header file for -include-pth">;
def warn_fe_macro_contains_embedded_newline : Warning<
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index e5793fa58b04..203ab1eed547 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -73,7 +73,7 @@ def : DiagGroup<"redundant-decls">;
def ReturnType : DiagGroup<"return-type">;
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
def : DiagGroup<"sequence-point">;
-def : DiagGroup<"shadow">;
+def Shadow : DiagGroup<"shadow">;
def : DiagGroup<"shorten-64-to-32">;
def SignCompare : DiagGroup<"sign-compare">;
def : DiagGroup<"synth">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 9a9b7cc85f6a..752be5df7a12 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -107,7 +107,15 @@ def warn_use_out_of_scope_declaration : Warning<
"use of out-of-scope declaration of %0">;
def err_inline_non_function : Error<
"'inline' can only appear on functions">;
-
+
+def warn_decl_shadow :
+ Warning<"declaration shadows a %select{"
+ "local variable|"
+ "variable in %2|"
+ "static data member of %2|"
+ "field of %2}1">,
+ InGroup<Shadow>, DefaultIgnore;
+
// C++ using declarations
def err_using_requires_qualname : Error<
"using declaration requires a qualified name">;
@@ -1529,8 +1537,7 @@ def err_forward_ref_enum : Error<
"ISO C++ forbids forward references to 'enum' types">;
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
-def err_misplaced_ivar : Error<"ivar may be placed in a class extension "
- "in non-fragile-abi2 mode only">;
+def err_misplaced_ivar : Error<"ivars may not be placed in categories">;
def ext_enum_value_not_int : Extension<
"ISO C restricts enumerator values to range of 'int' (%0 is too "
"%select{small|large}1)">;
@@ -1881,16 +1888,16 @@ def err_stmtexpr_file_scope : Error<
"statement expression not allowed at file scope">;
def warn_mixed_sign_comparison : Warning<
"comparison of integers of different signs: %0 and %1">,
- InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
+ InGroup<SignCompare>, DefaultIgnore;
def warn_mixed_sign_conditional : Warning<
"operands of ? are integers of different signs: %0 and %1">,
- InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
+ InGroup<SignCompare>, DefaultIgnore;
def warn_lunsigned_always_true_comparison : Warning<
"comparison of unsigned expression %0 is always %1">,
- InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
+ InGroup<SignCompare>, DefaultIgnore;
def warn_runsigned_always_true_comparison : Warning<
"comparison of %0 unsigned expression is always %1">,
- InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
+ InGroup<SignCompare>, DefaultIgnore;
def err_invalid_this_use : Error<
"invalid use of 'this' outside of a nonstatic member function">;
@@ -1944,11 +1951,7 @@ def ext_integer_complement_complex : Extension<
def error_nosetter_property_assignment : Error<
"setter method is needed to assign to object using property" " assignment syntax">;
def error_no_subobject_property_setting : Error<
- "cannot assign to a sub-structure of an ivar using property"
- " assignment syntax">;
-def error_no_subobject_property_getter_setting : Error<
- "cannot assign to a sub-structure returned via a getter using property"
- " assignment syntax">;
+ "expression is not assignable using property assignment syntax">;
def ext_freestanding_complex : Extension<
"complex numbers are an extension in a freestanding C99 implementation">;
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 34dfecd9b6a8..f7ea331e1cc7 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -200,19 +200,19 @@ public:
FullSourceLoc getInstantiationLoc() const;
FullSourceLoc getSpellingLoc() const;
- unsigned getInstantiationLineNumber() const;
- unsigned getInstantiationColumnNumber() const;
+ unsigned getInstantiationLineNumber(bool *Invalid = 0) const;
+ unsigned getInstantiationColumnNumber(bool *Invalid = 0) const;
- unsigned getSpellingLineNumber() const;
- unsigned getSpellingColumnNumber() const;
+ unsigned getSpellingLineNumber(bool *Invalid = 0) const;
+ unsigned getSpellingColumnNumber(bool *Invalid = 0) const;
- const char *getCharacterData() const;
+ const char *getCharacterData(bool *Invalid = 0) const;
- const llvm::MemoryBuffer* getBuffer() const;
+ const llvm::MemoryBuffer* getBuffer(bool *Invalid = 0) const;
/// getBufferData - Return a StringRef to the source buffer data for the
/// specified FileID.
- llvm::StringRef getBufferData() const;
+ llvm::StringRef getBufferData(bool *Invalid = 0) const;
/// getDecomposedLoc - Decompose the specified location into a raw FileID +
/// Offset pair. The first element is the FileID, the second is the
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index ef51a5888379..d1239694fc16 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -17,6 +17,7 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/Allocator.h"
#include "llvm/System/DataTypes.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/DenseMap.h"
#include <vector>
@@ -54,7 +55,8 @@ namespace SrcMgr {
class ContentCache {
/// Buffer - The actual buffer containing the characters from the input
/// file. This is owned by the ContentCache object.
- mutable const llvm::MemoryBuffer *Buffer;
+ /// The bit indicates whether the buffer is invalid.
+ mutable llvm::PointerIntPair<const llvm::MemoryBuffer *, 1, bool> Buffer;
public:
/// Reference to the file entry. This reference does not own
@@ -92,8 +94,9 @@ namespace SrcMgr {
unsigned getSizeBytesMapped() const;
void setBuffer(const llvm::MemoryBuffer *B) {
- assert(!Buffer && "MemoryBuffer already set.");
- Buffer = B;
+ assert(!Buffer.getPointer() && "MemoryBuffer already set.");
+ Buffer.setPointer(B);
+ Buffer.setInt(false);
}
/// \brief Replace the existing buffer (which will be deleted)
@@ -101,17 +104,19 @@ namespace SrcMgr {
void replaceBuffer(const llvm::MemoryBuffer *B);
ContentCache(const FileEntry *Ent = 0)
- : Buffer(0), Entry(Ent), SourceLineCache(0), NumLines(0) {}
+ : Buffer(0, false), Entry(Ent), SourceLineCache(0), NumLines(0) {}
~ContentCache();
/// The copy ctor does not allow copies where source object has either
/// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
/// is not transfered, so this is a logical error.
- ContentCache(const ContentCache &RHS) : Buffer(0), SourceLineCache(0) {
+ ContentCache(const ContentCache &RHS)
+ : Buffer(0, false), SourceLineCache(0)
+ {
Entry = RHS.Entry;
- assert (RHS.Buffer == 0 && RHS.SourceLineCache == 0
+ assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0
&& "Passed ContentCache object cannot own a buffer.");
NumLines = RHS.NumLines;
diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h
index 2728637ba497..2e0993ab52a1 100644
--- a/include/clang/Basic/Version.h
+++ b/include/clang/Basic/Version.h
@@ -22,7 +22,7 @@
// FIXME: Updates to this file must also update CMakeLists.txt and VER.
/// \brief Clang minor version
-#define CLANG_VERSION_MINOR 1
+#define CLANG_VERSION_MINOR 5
/// \brief Clang patchlevel version
// #define CLANG_VERSION_PATCHLEVEL 1
diff --git a/include/clang/Checker/BugReporter/BugReporter.h b/include/clang/Checker/BugReporter/BugReporter.h
index 6c41668ccece..2c15f2a40576 100644
--- a/include/clang/Checker/BugReporter/BugReporter.h
+++ b/include/clang/Checker/BugReporter/BugReporter.h
@@ -17,13 +17,15 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Checker/PathSensitive/GRState.h"
-#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/ImmutableSet.h"
#include <list>
namespace clang {
@@ -45,7 +47,7 @@ class ParentMap;
// Interface for individual bug reports.
//===----------------------------------------------------------------------===//
-class BugReporterVisitor {
+class BugReporterVisitor : public llvm::FoldingSetNode {
public:
virtual ~BugReporterVisitor();
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
@@ -53,6 +55,7 @@ public:
BugReporterContext& BRC) = 0;
virtual bool isOwnedByReporterContext() { return true; }
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
};
// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
@@ -385,16 +388,18 @@ public:
class BugReporterContext {
GRBugReporter &BR;
- std::vector<BugReporterVisitor*> Callbacks;
+ // Not the most efficient data structure, but we use an ImmutableList for the
+ // Callbacks because it is safe to make additions to list during iteration.
+ llvm::ImmutableList<BugReporterVisitor*>::Factory F;
+ llvm::ImmutableList<BugReporterVisitor*> Callbacks;
+ llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
public:
- BugReporterContext(GRBugReporter& br) : BR(br) {}
+ BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.GetEmptyList()) {}
virtual ~BugReporterContext();
- void addVisitor(BugReporterVisitor* visitor) {
- if (visitor) Callbacks.push_back(visitor);
- }
+ void addVisitor(BugReporterVisitor* visitor);
- typedef std::vector<BugReporterVisitor*>::iterator visitor_iterator;
+ typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
visitor_iterator visitor_begin() { return Callbacks.begin(); }
visitor_iterator visitor_end() { return Callbacks.end(); }
@@ -467,6 +472,7 @@ void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
const ExplodedNode *N);
+void registerNilReceiverVisitor(BugReporterContext &BRC);
} // end namespace clang::bugreporter
diff --git a/include/clang/Checker/PathSensitive/GRState.h b/include/clang/Checker/PathSensitive/GRState.h
index 1178143bccdd..657266b7508d 100644
--- a/include/clang/Checker/PathSensitive/GRState.h
+++ b/include/clang/Checker/PathSensitive/GRState.h
@@ -453,6 +453,7 @@ public:
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
+ const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
public:
diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h
index c660e7b7feee..edc338012ada 100644
--- a/include/clang/Checker/PathSensitive/Store.h
+++ b/include/clang/Checker/PathSensitive/Store.h
@@ -144,6 +144,7 @@ public:
}
virtual Store RemoveDeadBindings(Store store, Stmt* Loc,
+ const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h
index e0e0f779bf5a..85c6c3e3abcf 100644
--- a/include/clang/CodeGen/CodeGenOptions.h
+++ b/include/clang/CodeGen/CodeGenOptions.h
@@ -30,6 +30,9 @@ public:
};
unsigned AsmVerbose : 1; /// -dA, -fverbose-asm.
+ unsigned CXAAtExit : 1; /// Use __cxa_atexit for calling destructors.
+ unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
+ /// aliases to base ctors when possible.
unsigned DebugInfo : 1; /// Should generate deubg info (-g).
unsigned DisableFPElim : 1; /// Set when -fomit-frame-pointer is enabled.
unsigned DisableLLVMOpts : 1; /// Don't run any optimizations, for use in
@@ -53,8 +56,6 @@ public:
unsigned UnwindTables : 1; /// Emit unwind tables.
unsigned VerifyModule : 1; /// Control whether the module should be run
/// through the LLVM Verifier.
- unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
- /// aliases to base ctors when possible.
/// The code model to use (-mcmodel).
std::string CodeModel;
@@ -86,6 +87,8 @@ public:
public:
CodeGenOptions() {
AsmVerbose = 0;
+ CXAAtExit = 1;
+ CXXCtorDtorAliases = 0;
DebugInfo = 0;
DisableFPElim = 0;
DisableLLVMOpts = 0;
@@ -103,7 +106,6 @@ public:
UnrollLoops = 0;
UnwindTables = 0;
VerifyModule = 1;
- CXXCtorDtorAliases = 0;
Inlining = NoInlining;
RelocationModel = "pic";
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 1ecd8d6adaf6..feebbc78864f 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -227,8 +227,6 @@ def code_completion_macros : Flag<"-code-completion-macros">,
HelpText<"Include macros in code-completion results">;
def disable_free : Flag<"-disable-free">,
HelpText<"Disable freeing of memory on exit">;
-def empty_input_only : Flag<"-empty-input-only">,
- HelpText<"Force running on an empty input file">;
def help : Flag<"-help">,
HelpText<"Print this help text">;
def _help : Flag<"--help">, Alias<help>;
@@ -262,6 +260,8 @@ def analyze : Flag<"-analyze">,
HelpText<"Run static analysis engine">;
def dump_tokens : Flag<"-dump-tokens">,
HelpText<"Run preprocessor, dump internal rep of tokens">;
+def init_only : Flag<"-init-only">,
+ HelpText<"Only execute frontend initialization">;
def parse_noop : Flag<"-parse-noop">,
HelpText<"Run parser with noop callbacks (for timings)">;
def fsyntax_only : Flag<"-fsyntax-only">,
@@ -355,10 +355,12 @@ def fno_elide_constructors : Flag<"-fno-elide-constructors">,
HelpText<"Disable C++ copy constructor elision">;
def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">,
HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">;
-def fno_signed_char : Flag<"-fno-signed-char">,
- HelpText<"Char is unsigned">;
def fno_operator_names : Flag<"-fno-operator-names">,
HelpText<"Do not treat C++ operator name keywords as synonyms for operators">;
+def fno_signed_char : Flag<"-fno-signed-char">,
+ HelpText<"Char is unsigned">;
+def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">,
+ HelpText<"Don't use __cxa_atexit for calling destructors">;
def fconstant_string_class : Separate<"-fconstant-string-class">,
MetaVarName<"<class name>">,
HelpText<"Specify the class to use for constant Objective-C string objects.">;
@@ -448,7 +450,9 @@ def U : JoinedOrSeparate<"-U">, MetaVarName<"<macro>">,
HelpText<"Undefine the specified macro">;
def undef : Flag<"-undef">, MetaVarName<"<macro>">,
HelpText<"undef all system defines">;
-
+def detailed_preprocessing_record : Flag<"-detailed-preprocessing-record">,
+ HelpText<"include a detailed record of preprocessing actions">;
+
//===----------------------------------------------------------------------===//
// Preprocessed Output Options
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index 59c3946a2cb5..f49c3b97c1c4 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -83,6 +83,9 @@ public:
/// Name to use when calling the generic gcc.
std::string CCCGenericGCCName;
+ /// The file to log CC_PRINT_OPTIONS output to, if enabled.
+ const char *CCPrintOptionsFilename;
+
/// Whether the driver should follow g++ like behavior.
unsigned CCCIsCXX : 1;
@@ -92,6 +95,10 @@ public:
/// Only print tool bindings, don't build any jobs.
unsigned CCCPrintBindings : 1;
+ /// Set CC_PRINT_OPTIONS mode, which is like -v but logs the commands to
+ /// CCPrintOptionsFilename or to stderr.
+ unsigned CCPrintOptions : 1;
+
private:
/// Whether to check that input files exist when constructing compilation
/// jobs.
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 3eb74ca59525..71258f9814be 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -229,6 +229,7 @@ def exported__symbols__list : Separate<"-exported_symbols_list">;
def e : JoinedOrSeparate<"-e">;
def fPIC : Flag<"-fPIC">, Group<f_Group>;
def fPIE : Flag<"-fPIE">, Group<f_Group>;
+def faccess_control : Flag<"-faccess-control">, Group<f_Group>;
def fapple_kext : Flag<"-fapple-kext">, Group<f_Group>;
def fasm_blocks : Flag<"-fasm-blocks">, Group<clang_ignored_f_Group>;
def fassume_sane_operator_new : Flag<"-fassume-sane-operator-new">, Group<f_Group>;
@@ -262,6 +263,7 @@ def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>;
def fencoding_EQ : Joined<"-fencoding=">, Group<f_Group>;
def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
+def fhosted : Flag<"-fhosted">, Group<f_Group>;
def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>;
def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>;
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
@@ -282,6 +284,7 @@ def fmudflapth : Flag<"-fmudflapth">, Group<f_Group>;
def fmudflap : Flag<"-fmudflap">, Group<f_Group>;
def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>;
def fnext_runtime : Flag<"-fnext-runtime">, Group<f_Group>;
+def fno_access_control : Flag<"-fno-access-control">, Group<f_Group>;
def fno_asynchronous_unwind_tables : Flag<"-fno-asynchronous-unwind-tables">, Group<f_Group>;
def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, Group<f_Group>;
def fno_blocks : Flag<"-fno-blocks">, Group<f_Group>;
@@ -300,6 +303,7 @@ def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>;
def fno_inline_functions : Flag<"-fno-inline-functions">, Group<clang_ignored_f_Group>;
def fno_inline : Flag<"-fno-inline">, Group<clang_ignored_f_Group>;
def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_ignored_f_Group>;
+def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Group>;
def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group<f_Group>;
def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group<f_Group>;
@@ -312,6 +316,7 @@ def fno_show_source_location : Flag<"-fno-show-source-location">, Group<f_Group>
def fno_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>;
def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<clang_ignored_f_Group>;
def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group<f_Group>;
+def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>;
def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group<f_Group>;
def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>;
def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
@@ -360,6 +365,7 @@ def funit_at_a_time : Flag<"-funit-at-a-time">, Group<f_Group>;
def funsigned_bitfields : Flag<"-funsigned-bitfields">, Group<f_Group>;
def funsigned_char : Flag<"-funsigned-char">, Group<f_Group>;
def funwind_tables : Flag<"-funwind-tables">, Group<f_Group>;
+def fuse_cxa_atexit : Flag<"-fuse-cxa-atexit">, Group<f_Group>;
def fverbose_asm : Flag<"-fverbose-asm">, Group<f_Group>;
def fvisibility_EQ : Joined<"-fvisibility=">, Group<f_Group>;
def fwritable_strings : Flag<"-fwritable-strings">, Group<f_Group>;
@@ -390,7 +396,7 @@ def iwithprefix : JoinedOrSeparate<"-iwithprefix">, Group<clang_i_Group>;
def iwithsysroot : JoinedOrSeparate<"-iwithsysroot">, Group<i_Group>;
def i : Joined<"-i">, Group<i_Group>;
def keep__private__externs : Flag<"-keep_private_externs">;
-def l : JoinedOrSeparate<"-l">, Flags<[LinkerInput]>;
+def l : JoinedOrSeparate<"-l">, Flags<[LinkerInput, RenderJoined]>;
def m32 : Flag<"-m32">, Group<m_Group>, Flags<[DriverOption]>;
def m3dnowa : Flag<"-m3dnowa">, Group<m_x86_Features_Group>;
def m3dnow : Flag<"-m3dnow">, Group<m_x86_Features_Group>;
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 27ec12e4e4cd..61db323a12bb 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -14,12 +14,14 @@
#ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
#define LLVM_CLANG_FRONTEND_ASTUNIT_H
+#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/OwningPtr.h"
#include "clang/Basic/FileManager.h"
#include "clang/Index/ASTLocation.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/System/Path.h"
+#include <map>
#include <string>
#include <vector>
#include <cassert>
@@ -46,6 +48,11 @@ using namespace idx;
/// \brief Utility class for loading a ASTContext from a PCH file.
///
class ASTUnit {
+public:
+ typedef std::map<FileID, std::vector<PreprocessedEntity *> >
+ PreprocessedEntitiesByFileMap;
+private:
+
FileManager FileMgr;
SourceManager SourceMgr;
@@ -53,7 +60,7 @@ class ASTUnit {
llvm::OwningPtr<TargetInfo> Target;
llvm::OwningPtr<Preprocessor> PP;
llvm::OwningPtr<ASTContext> Ctx;
-
+
/// Optional owned invocation, just used to make the invocation used in
/// LoadFromCommandLine available.
llvm::OwningPtr<CompilerInvocation> Invocation;
@@ -89,6 +96,15 @@ class ASTUnit {
/// destroyed.
llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles;
+ /// \brief A mapping from file IDs to the set of preprocessed entities
+ /// stored in that file.
+ ///
+ /// FIXME: This is just an optimization hack to avoid searching through
+ /// many preprocessed entities during cursor traversal in the CIndex library.
+ /// Ideally, we would just be able to perform a binary search within the
+ /// list of preprocessed entities.
+ PreprocessedEntitiesByFileMap PreprocessedEntitiesByFile;
+
/// \brief Simple hack to allow us to assert that ASTUnit is not being
/// used concurrently, which is not supported.
///
@@ -162,6 +178,12 @@ public:
return TopLevelDecls;
}
+ /// \brief Retrieve the mapping from File IDs to the preprocessed entities
+ /// within that file.
+ PreprocessedEntitiesByFileMap &getPreprocessedEntitiesByFile() {
+ return PreprocessedEntitiesByFile;
+ }
+
// Retrieve the diagnostics associated with this AST
typedef const StoredDiagnostic * diag_iterator;
diag_iterator diag_begin() const { return Diagnostics.begin(); }
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 828e9b5bf605..3444b640f01d 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -34,7 +34,6 @@ class ExternalASTSource;
class FileManager;
class FrontendAction;
class Preprocessor;
-class Source;
class SourceManager;
class TargetInfo;
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 5348e6b1ee9c..a7b6aa7e752f 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -18,6 +18,22 @@ namespace clang {
class FixItRewriter;
//===----------------------------------------------------------------------===//
+// Custom Consumer Actions
+//===----------------------------------------------------------------------===//
+
+class InitOnlyAction : public FrontendAction {
+ virtual void ExecuteAction();
+
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile);
+
+public:
+ // Don't claim to only use the preprocessor, we want to follow the AST path,
+ // but do nothing.
+ virtual bool usesPreprocessorOnly() const { return false; }
+};
+
+//===----------------------------------------------------------------------===//
// AST Consumer Actions
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 80ba77864a5b..ee3811a30b94 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -36,6 +36,7 @@ namespace frontend {
GeneratePCH, ///< Generate pre-compiled header.
GeneratePTH, ///< Generate pre-tokenized header.
InheritanceView, ///< View C++ inheritance for a specified class.
+ InitOnly, ///< Only execute frontend initialization.
ParseNoop, ///< Parse with noop callbacks.
ParsePrintCallbacks, ///< Parse and print each callback.
ParseSyntaxOnly, ///< Parse and perform semantic analysis.
@@ -71,9 +72,6 @@ public:
unsigned DebugCodeCompletionPrinter : 1; ///< Use the debug printer for code
/// completion results.
unsigned DisableFree : 1; ///< Disable memory freeing on exit.
- unsigned EmptyInputOnly : 1; ///< Force input files to be treated
- /// as if they were empty, for timing
- /// the frontend startup.
unsigned RelocatablePCH : 1; ///< When generating PCH files,
/// instruct the PCH writer to create
/// relocatable PCH files.
@@ -117,7 +115,6 @@ public:
FrontendOptions() {
DebugCodeCompletionPrinter = 1;
DisableFree = 0;
- EmptyInputOnly = 0;
ProgramAction = frontend::ParseSyntaxOnly;
ActionName = "";
RelocatablePCH = 0;
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index e234e9838a12..f975c497bee9 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -215,17 +215,18 @@ namespace clang {
/// generate the precompiled header.
ORIGINAL_FILE_NAME = 19,
- /// \brief Record code for the sorted array of source ranges where
- /// comments were encountered in the source code.
- COMMENT_RANGES = 20,
+ /// Record #20 intentionally left blank.
/// \brief Record code for the version control branch and revision
/// information of the compiler used to build this PCH file.
VERSION_CONTROL_BRANCH_REVISION = 21,
/// \brief Record code for the array of unused static functions.
- UNUSED_STATIC_FUNCS = 22
+ UNUSED_STATIC_FUNCS = 22,
+ /// \brief Record code for the table of offsets to macro definition
+ /// entries in the preprocessing record.
+ MACRO_DEFINITION_OFFSETS = 23
};
/// \brief Record types used within a source manager block.
@@ -245,10 +246,7 @@ namespace clang {
SM_SLOC_INSTANTIATION_ENTRY = 4,
/// \brief Describes the SourceManager's line table, with
/// information about #line directives.
- SM_LINE_TABLE = 5,
- /// \brief Describes one header file info [isImport, DirInfo, NumIncludes]
- /// ControllingMacro is optional.
- SM_HEADER_FILE_INFO = 6
+ SM_LINE_TABLE = 5
};
/// \brief Record types used within a preprocessor block.
@@ -267,7 +265,14 @@ namespace clang {
/// \brief Describes one token.
/// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags]
- PP_TOKEN = 3
+ PP_TOKEN = 3,
+
+ /// \brief Describes a macro instantiation within the preprocessing
+ /// record.
+ PP_MACRO_INSTANTIATION = 4,
+
+ /// \brief Describes a macro definition within the preprocessing record.
+ PP_MACRO_DEFINITION = 5
};
/// \defgroup PCHAST Precompiled header AST constants
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index 065006fce5c4..73c1bf4cce5c 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -21,6 +21,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/TemplateBase.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
+#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
@@ -53,6 +54,7 @@ class Decl;
class DeclContext;
class GotoStmt;
class LabelStmt;
+class MacroDefinition;
class NamedDecl;
class Preprocessor;
class Sema;
@@ -106,7 +108,7 @@ public:
}
/// \brief Receives a HeaderFileInfo entry.
- virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {}
+ virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {}
/// \brief Receives __COUNTER__ value.
virtual void ReadCounter(unsigned Value) {}
@@ -130,8 +132,11 @@ public:
FileID PCHBufferID,
llvm::StringRef OriginalFileName,
std::string &SuggestedPredefines);
- virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI);
+ virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID);
virtual void ReadCounter(unsigned Value);
+
+private:
+ void Error(const char *Msg);
};
/// \brief Reads a precompiled head containing the contents of a
@@ -148,13 +153,14 @@ public:
/// actually required will be de-serialized.
class PCHReader
: public ExternalPreprocessorSource,
+ public ExternalPreprocessingRecordSource,
public ExternalSemaSource,
public IdentifierInfoLookup,
public ExternalIdentifierLookup,
public ExternalSLocEntrySource {
public:
enum PCHReadResult { Success, Failure, IgnorePCH };
-
+ friend class PCHValidator;
private:
/// \ brief The receiver of some callbacks invoked by PCHReader.
llvm::OwningPtr<PCHReaderListener> Listener;
@@ -293,12 +299,17 @@ private:
/// been loaded.
llvm::SmallVector<Selector, 16> SelectorsLoaded;
- /// \brief A sorted array of source ranges containing comments.
- SourceRange *Comments;
-
- /// \brief The number of source ranges in the Comments array.
- unsigned NumComments;
-
+ /// \brief Offsets of all of the macro definitions in the preprocessing
+ /// record in the PCH file.
+ const uint32_t *MacroDefinitionOffsets;
+
+ /// \brief The macro definitions we have already loaded.
+ llvm::SmallVector<MacroDefinition *, 16> MacroDefinitionsLoaded;
+
+ /// \brief The number of preallocated preprocessing entities in the
+ /// preprocessing record.
+ unsigned NumPreallocatedPreprocessingEntities;
+
/// \brief The set of external definitions stored in the the PCH
/// file.
llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
@@ -472,7 +483,7 @@ private:
///
/// This routine should only be used for fatal errors that have to
/// do with non-routine failures (e.g., corrupted PCH file).
- bool Error(const char *Msg);
+ void Error(const char *Msg);
PCHReader(const PCHReader&); // do not implement
PCHReader &operator=(const PCHReader &); // do not implement
@@ -524,9 +535,7 @@ public:
}
/// \brief Set the Preprocessor to use.
- void setPreprocessor(Preprocessor &pp) {
- PP = &pp;
- }
+ void setPreprocessor(Preprocessor &pp);
/// \brief Sets and initializes the given Context.
void InitializeContext(ASTContext &Context);
@@ -547,14 +556,9 @@ public:
/// which contains a (typically-empty) subset of the predefines
/// build prior to including the precompiled header.
const std::string &getSuggestedPredefines() { return SuggestedPredefines; }
-
- /// \brief Reads the source ranges that correspond to comments from
- /// an external AST source.
- ///
- /// \param Comments the contents of this vector will be
- /// replaced with the sorted set of source ranges corresponding to
- /// comments in the source code.
- virtual void ReadComments(std::vector<SourceRange> &Comments);
+
+ /// \brief Read preprocessed entities into the
+ virtual void ReadPreprocessedEntities();
/// \brief Reads a TemplateArgumentLocInfo appropriate for the
/// given TemplateArgument kind.
@@ -724,6 +728,9 @@ public:
/// \brief Read the set of macros defined by this external macro source.
virtual void ReadDefinedMacros();
+ /// \brief Retrieve the macro definition with the given ID.
+ MacroDefinition *getMacroDefinition(pch::IdentID ID);
+
/// \brief Retrieve the AST context that this PCH reader
/// supplements.
ASTContext *getContext() { return Context; }
@@ -790,6 +797,10 @@ private:
uint64_t Offset;
};
+inline void PCHValidator::Error(const char *Msg) {
+ Reader.Error(Msg);
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h
index 212130e2ea62..e006de524ca3 100644
--- a/include/clang/Frontend/PCHWriter.h
+++ b/include/clang/Frontend/PCHWriter.h
@@ -33,6 +33,7 @@ namespace clang {
class ASTContext;
class LabelStmt;
+class MacroDefinition;
class MemorizeStatCalls;
class Preprocessor;
class Sema;
@@ -160,6 +161,14 @@ private:
/// defined.
llvm::DenseMap<const IdentifierInfo *, uint64_t> MacroOffsets;
+ /// \brief Mapping from macro definitions (as they occur in the preprocessing
+ /// record) to the index into the macro definitions table.
+ llvm::DenseMap<const MacroDefinition *, pch::IdentID> MacroDefinitions;
+
+ /// \brief Mapping from the macro definition indices in \c MacroDefinitions
+ /// to the corresponding offsets within the preprocessor block.
+ std::vector<uint32_t> MacroDefinitionOffsets;
+
/// \brief Declarations encountered that might be external
/// definitions.
///
@@ -206,7 +215,6 @@ private:
const Preprocessor &PP,
const char* isysroot);
void WritePreprocessor(const Preprocessor &PP);
- void WriteComments(ASTContext &Context);
void WriteType(QualType T);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
@@ -234,6 +242,9 @@ public:
///
/// \param isysroot if non-NULL, write a relocatable PCH file whose headers
/// are relative to the given system root.
+ ///
+ /// \param PPRec Record of the preprocessing actions that occurred while
+ /// preprocessing this file, e.g., macro instantiations
void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const char* isysroot);
@@ -269,6 +280,10 @@ public:
return MacroOffsets[II];
}
+ /// \brief Retrieve the ID number corresponding to the given macro
+ /// definition.
+ pch::IdentID getMacroDefinitionID(MacroDefinition *MD);
+
/// \brief Emit a reference to a type.
void AddTypeRef(QualType T, RecordData &Record);
diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h
index 7ba7c5c38dab..891359b74784 100644
--- a/include/clang/Frontend/PreprocessorOptions.h
+++ b/include/clang/Frontend/PreprocessorOptions.h
@@ -36,6 +36,10 @@ public:
unsigned UsePredefines : 1; /// Initialize the preprocessor with the compiler
/// and target specific predefines.
+ unsigned DetailedRecord : 1; /// Whether we should maintain a detailed
+ /// record of all macro definitions and
+ /// instantiations.
+
/// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude;
@@ -77,7 +81,7 @@ public:
}
public:
- PreprocessorOptions() : UsePredefines(true) {}
+ PreprocessorOptions() : UsePredefines(true), DetailedRecord(false) {}
void addMacroDef(llvm::StringRef Name) {
Macros.push_back(std::make_pair(Name, false));
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 7f43b2ad80ff..c1d483164a21 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -59,7 +59,7 @@ void InitializePreprocessor(Preprocessor &PP,
/// ProcessWarningOptions - Initialize the diagnostic client and process the
/// warning options specified on the command line.
-bool ProcessWarningOptions(Diagnostic &Diags, const DiagnosticOptions &Opts);
+void ProcessWarningOptions(Diagnostic &Diags, const DiagnosticOptions &Opts);
/// DoPrintPreprocessedInput - Implement -E mode.
void DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream* OS,
diff --git a/include/clang/Frontend/VerifyDiagnosticsClient.h b/include/clang/Frontend/VerifyDiagnosticsClient.h
index 6f7ebbe537f9..08adbb04d166 100644
--- a/include/clang/Frontend/VerifyDiagnosticsClient.h
+++ b/include/clang/Frontend/VerifyDiagnosticsClient.h
@@ -16,7 +16,6 @@
namespace clang {
class Diagnostic;
-class SourceMgr;
class TextDiagnosticBuffer;
/// VerifyDiagnosticsClient - Create a diagnostic client which will use markers
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 16b8379045e5..978585caf0e4 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -214,9 +214,10 @@ public:
void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
- typedef std::vector<HeaderFileInfo>::iterator header_file_iterator;
- header_file_iterator header_file_begin() { return FileInfo.begin(); }
- header_file_iterator header_file_end() { return FileInfo.end(); }
+ typedef std::vector<HeaderFileInfo>::const_iterator header_file_iterator;
+ header_file_iterator header_file_begin() const { return FileInfo.begin(); }
+ header_file_iterator header_file_end() const { return FileInfo.end(); }
+ unsigned header_file_size() const { return FileInfo.size(); }
// Used by PCHReader.
void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID);
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
new file mode 100644
index 000000000000..ef28af9b7fe0
--- /dev/null
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -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
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 2b27a06070f8..23c118d1fc63 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -43,7 +43,8 @@ class ScratchBuffer;
class TargetInfo;
class PPCallbacks;
class DirectoryLookup;
-
+class PreprocessingRecord;
+
/// Preprocessor - This object engages in a tight little dance with the lexer to
/// efficiently preprocess tokens. Lexers know only about tokens within a
/// single source file, and don't know anything about preprocessor-level issues
@@ -209,6 +210,13 @@ class Preprocessor {
unsigned NumCachedTokenLexers;
TokenLexer *TokenLexerCache[TokenLexerCacheSize];
+ /// \brief A record of the macro definitions and instantiations that
+ /// occurred during preprocessing.
+ ///
+ /// This is an optional side structure that can be enabled with
+ /// \c createPreprocessingRecord() prior to preprocessing.
+ PreprocessingRecord *Record;
+
private: // Cached tokens state.
typedef llvm::SmallVector<Token, 1> CachedTokensTy;
@@ -348,9 +356,17 @@ public:
/// It is an error to remove a handler that has not been registered.
void RemoveCommentHandler(CommentHandler *Handler);
+ /// \brief Retrieve the preprocessing record, or NULL if there is no
+ /// preprocessing record.
+ PreprocessingRecord *getPreprocessingRecord() const { return Record; }
+
+ /// \brief Create a new preprocessing record, which will keep track of
+ /// all macro expansions, macro definitions, etc.
+ void createPreprocessingRecord();
+
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
- void EnterMainSourceFile();
+ bool EnterMainSourceFile();
/// EnterSourceFile - Add a source file to the top of the include stack and
/// start lexing tokens from it instead of the current buffer. Return true
@@ -595,7 +611,7 @@ public:
// Otherwise, fall back on getCharacterData, which is slower, but always
// works.
- return *SourceMgr.getCharacterData(Tok.getLocation());
+ return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid);
}
/// CreateString - Plop the specified string into a scratch buffer and set the
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index f211b5ca3a69..b79e698d50c9 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -153,10 +153,6 @@ public:
/// an empty string if not. This is used for pretty crash reporting.
virtual std::string getDeclName(DeclPtrTy D) { return ""; }
- /// \brief Invoked for each comment in the source code, providing the source
- /// range that contains the comment.
- virtual void ActOnComment(SourceRange Comment) { }
-
//===--------------------------------------------------------------------===//
// Declaration Tracking Callbacks.
//===--------------------------------------------------------------------===//
@@ -727,9 +723,17 @@ public:
/// ActOnTagFinishDefinition - Invoked once we have finished parsing
/// the definition of a tag (enumeration, class, struct, or union).
+ ///
+ /// The scope is the scope of the tag definition.
virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
SourceLocation RBraceLoc) { }
+ /// ActOnTagDefinitionError - Invoked if there's an unrecoverable
+ /// error parsing the definition of a tag.
+ ///
+ /// The scope is the scope of the tag definition.
+ virtual void ActOnTagDefinitionError(Scope *S, DeclPtrTy TagDecl) { }
+
virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl,
DeclPtrTy LastEnumConstant,
SourceLocation IdLoc, IdentifierInfo *Id,
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index f034aa10ce30..411162b18209 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -90,7 +90,6 @@ class Parser {
llvm::OwningPtr<PragmaHandler> PackHandler;
llvm::OwningPtr<PragmaHandler> UnusedHandler;
llvm::OwningPtr<PragmaHandler> WeakHandler;
- llvm::OwningPtr<clang::CommentHandler> CommentHandler;
/// Whether the '>' token acts as an operator or not. This will be
/// true except when we are parsing an expression within a C++
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 8230cde3b2d5..7f5c9b1ec1e6 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -43,8 +43,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0),
ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
- SourceMgr(SM), LangOpts(LOpts),
- LoadedExternalComments(false), FreeMemory(FreeMem), Target(t),
+ SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t),
Idents(idents), Selectors(sels),
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
ObjCIdRedefinitionType = QualType();
@@ -413,201 +412,6 @@ namespace {
};
}
-/// \brief Determine whether the given comment is a Doxygen-style comment.
-///
-/// \param Start the start of the comment text.
-///
-/// \param End the end of the comment text.
-///
-/// \param Member whether we want to check whether this is a member comment
-/// (which requires a < after the Doxygen-comment delimiter). Otherwise,
-/// we only return true when we find a non-member comment.
-static bool
-isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
- bool Member = false) {
- bool Invalid = false;
- const char *BufferStart
- = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin()),
- &Invalid).data();
- if (Invalid)
- return false;
-
- const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin());
- const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd());
-
- if (End - Start < 4)
- return false;
-
- assert(Start[0] == '/' && "Not a comment?");
- if (Start[1] == '*' && !(Start[2] == '!' || Start[2] == '*'))
- return false;
- if (Start[1] == '/' && !(Start[2] == '!' || Start[2] == '/'))
- return false;
-
- return (Start[3] == '<') == Member;
-}
-
-/// \brief Retrieve the comment associated with the given declaration, if
-/// it has one.
-const char *ASTContext::getCommentForDecl(const Decl *D) {
- if (!D)
- return 0;
-
- // Check whether we have cached a comment string for this declaration
- // already.
- llvm::DenseMap<const Decl *, std::string>::iterator Pos
- = DeclComments.find(D);
- if (Pos != DeclComments.end())
- return Pos->second.c_str();
-
- // If we have an external AST source and have not yet loaded comments from
- // that source, do so now.
- if (ExternalSource && !LoadedExternalComments) {
- std::vector<SourceRange> LoadedComments;
- ExternalSource->ReadComments(LoadedComments);
-
- if (!LoadedComments.empty())
- Comments.insert(Comments.begin(), LoadedComments.begin(),
- LoadedComments.end());
-
- LoadedExternalComments = true;
- }
-
- // If there are no comments anywhere, we won't find anything.
- if (Comments.empty())
- return 0;
-
- // If the declaration doesn't map directly to a location in a file, we
- // can't find the comment.
- SourceLocation DeclStartLoc = D->getLocStart();
- if (DeclStartLoc.isInvalid() || !DeclStartLoc.isFileID())
- return 0;
-
- // Find the comment that occurs just before this declaration.
- std::vector<SourceRange>::iterator LastComment
- = std::lower_bound(Comments.begin(), Comments.end(),
- SourceRange(DeclStartLoc),
- BeforeInTranslationUnit(&SourceMgr));
-
- // Decompose the location for the start of the declaration and find the
- // beginning of the file buffer.
- std::pair<FileID, unsigned> DeclStartDecomp
- = SourceMgr.getDecomposedLoc(DeclStartLoc);
- bool Invalid = false;
- const char *FileBufferStart
- = SourceMgr.getBufferData(DeclStartDecomp.first, &Invalid).data();
- if (Invalid)
- return 0;
-
- // First check whether we have a comment for a member.
- if (LastComment != Comments.end() &&
- !isa<TagDecl>(D) && !isa<NamespaceDecl>(D) &&
- isDoxygenComment(SourceMgr, *LastComment, true)) {
- std::pair<FileID, unsigned> LastCommentEndDecomp
- = SourceMgr.getDecomposedLoc(LastComment->getEnd());
- if (DeclStartDecomp.first == LastCommentEndDecomp.first &&
- SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second)
- == SourceMgr.getLineNumber(LastCommentEndDecomp.first,
- LastCommentEndDecomp.second)) {
- // The Doxygen member comment comes after the declaration starts and
- // is on the same line and in the same file as the declaration. This
- // is the comment we want.
- std::string &Result = DeclComments[D];
- Result.append(FileBufferStart +
- SourceMgr.getFileOffset(LastComment->getBegin()),
- FileBufferStart + LastCommentEndDecomp.second + 1);
- return Result.c_str();
- }
- }
-
- if (LastComment == Comments.begin())
- return 0;
- --LastComment;
-
- // Decompose the end of the comment.
- std::pair<FileID, unsigned> LastCommentEndDecomp
- = SourceMgr.getDecomposedLoc(LastComment->getEnd());
-
- // If the comment and the declaration aren't in the same file, then they
- // aren't related.
- if (DeclStartDecomp.first != LastCommentEndDecomp.first)
- return 0;
-
- // Check that we actually have a Doxygen comment.
- if (!isDoxygenComment(SourceMgr, *LastComment))
- return 0;
-
- // Compute the starting line for the declaration and for the end of the
- // comment (this is expensive).
- unsigned DeclStartLine
- = SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second);
- unsigned CommentEndLine
- = SourceMgr.getLineNumber(LastCommentEndDecomp.first,
- LastCommentEndDecomp.second);
-
- // If the comment does not end on the line prior to the declaration, then
- // the comment is not associated with the declaration at all.
- if (CommentEndLine + 1 != DeclStartLine)
- return 0;
-
- // We have a comment, but there may be more comments on the previous lines.
- // Keep looking so long as the comments are still Doxygen comments and are
- // still adjacent.
- unsigned ExpectedLine
- = SourceMgr.getSpellingLineNumber(LastComment->getBegin()) - 1;
- std::vector<SourceRange>::iterator FirstComment = LastComment;
- while (FirstComment != Comments.begin()) {
- // Look at the previous comment
- --FirstComment;
- std::pair<FileID, unsigned> Decomp
- = SourceMgr.getDecomposedLoc(FirstComment->getEnd());
-
- // If this previous comment is in a different file, we're done.
- if (Decomp.first != DeclStartDecomp.first) {
- ++FirstComment;
- break;
- }
-
- // If this comment is not a Doxygen comment, we're done.
- if (!isDoxygenComment(SourceMgr, *FirstComment)) {
- ++FirstComment;
- break;
- }
-
- // If the line number is not what we expected, we're done.
- unsigned Line = SourceMgr.getLineNumber(Decomp.first, Decomp.second);
- if (Line != ExpectedLine) {
- ++FirstComment;
- break;
- }
-
- // Set the next expected line number.
- ExpectedLine
- = SourceMgr.getSpellingLineNumber(FirstComment->getBegin()) - 1;
- }
-
- // The iterator range [FirstComment, LastComment] contains all of the
- // BCPL comments that, together, are associated with this declaration.
- // Form a single comment block string for this declaration that concatenates
- // all of these comments.
- std::string &Result = DeclComments[D];
- while (FirstComment != LastComment) {
- std::pair<FileID, unsigned> DecompStart
- = SourceMgr.getDecomposedLoc(FirstComment->getBegin());
- std::pair<FileID, unsigned> DecompEnd
- = SourceMgr.getDecomposedLoc(FirstComment->getEnd());
- Result.append(FileBufferStart + DecompStart.second,
- FileBufferStart + DecompEnd.second + 1);
- ++FirstComment;
- }
-
- // Append the last comment line.
- Result.append(FileBufferStart +
- SourceMgr.getFileOffset(LastComment->getBegin()),
- FileBufferStart + LastCommentEndDecomp.second + 1);
- return Result.c_str();
-}
-
//===----------------------------------------------------------------------===//
// Type Sizing and Analysis
//===----------------------------------------------------------------------===//
@@ -4315,6 +4119,41 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
return false;
}
+/// canAssignObjCInterfacesInBlockPointer - This routine is specifically written
+/// for providing type-safty for objective-c pointers used to pass/return
+/// arguments in block literals. When passed as arguments, passing 'A*' where
+/// 'id' is expected is not OK. Passing 'Sub *" where 'Super *" is expected is
+/// not OK. For the return type, the opposite is not OK.
+bool ASTContext::canAssignObjCInterfacesInBlockPointer(
+ const ObjCObjectPointerType *LHSOPT,
+ const ObjCObjectPointerType *RHSOPT) {
+ if (RHSOPT->isObjCBuiltinType())
+ return true;
+
+ if (LHSOPT->isObjCBuiltinType()) {
+ return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
+ }
+
+ if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
+ return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
+ QualType(RHSOPT,0),
+ false);
+
+ const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
+ const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
+ if (LHS && RHS) { // We have 2 user-defined types.
+ if (LHS != RHS) {
+ if (LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
+ return false;
+ if (RHS->getDecl()->isSuperClassOf(LHS->getDecl()))
+ return true;
+ }
+ else
+ return true;
+ }
+ return false;
+}
+
/// getIntersectionOfProtocols - This routine finds the intersection of set
/// of protocols inherited from two distinct objective-c pointer objects.
/// It is used to build composite qualifier list of the composite type of
@@ -4451,7 +4290,12 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
return !mergeTypes(LHS, RHS).isNull();
}
-QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
+bool ASTContext::typesAreBlockPointerCompatible(QualType LHS, QualType RHS) {
+ return !mergeTypes(LHS, RHS, true).isNull();
+}
+
+QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
+ bool OfBlockPointer) {
const FunctionType *lbase = lhs->getAs<FunctionType>();
const FunctionType *rbase = rhs->getAs<FunctionType>();
const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase);
@@ -4460,7 +4304,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
bool allRTypes = true;
// Check return type
- QualType retType = mergeTypes(lbase->getResultType(), rbase->getResultType());
+ QualType retType;
+ if (OfBlockPointer)
+ retType = mergeTypes(rbase->getResultType(), lbase->getResultType(), true);
+ else
+ retType = mergeTypes(lbase->getResultType(), rbase->getResultType());
if (retType.isNull()) return QualType();
if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType()))
allLTypes = false;
@@ -4500,7 +4348,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
for (unsigned i = 0; i < lproto_nargs; i++) {
QualType largtype = lproto->getArgType(i).getUnqualifiedType();
QualType rargtype = rproto->getArgType(i).getUnqualifiedType();
- QualType argtype = mergeTypes(largtype, rargtype);
+ QualType argtype = mergeTypes(largtype, rargtype, OfBlockPointer);
if (argtype.isNull()) return QualType();
types.push_back(argtype);
if (getCanonicalType(argtype) != getCanonicalType(largtype))
@@ -4554,7 +4402,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
return getFunctionNoProtoType(retType, NoReturn, lcc);
}
-QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
+QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
+ bool OfBlockPointer) {
// C++ [expr]: If an expression initially has the type "reference to T", the
// type is adjusted to "T" prior to any further analysis, the expression
// designates the object or function denoted by the reference, and the
@@ -4681,7 +4530,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
// Merge two block pointer types, while trying to preserve typedef info
QualType LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType();
QualType RHSPointee = RHS->getAs<BlockPointerType>()->getPointeeType();
- QualType ResultType = mergeTypes(LHSPointee, RHSPointee);
+ QualType ResultType = mergeTypes(LHSPointee, RHSPointee, OfBlockPointer);
if (ResultType.isNull()) return QualType();
if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType))
return LHS;
@@ -4732,7 +4581,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
ArrayType::ArraySizeModifier(), 0);
}
case Type::FunctionNoProto:
- return mergeFunctionTypes(LHS, RHS);
+ return mergeFunctionTypes(LHS, RHS, OfBlockPointer);
case Type::Record:
case Type::Enum:
return QualType();
@@ -4761,12 +4610,19 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return QualType();
}
case Type::ObjCObjectPointer: {
+ if (OfBlockPointer) {
+ if (canAssignObjCInterfacesInBlockPointer(
+ LHS->getAs<ObjCObjectPointerType>(),
+ RHS->getAs<ObjCObjectPointerType>()))
+ return LHS;
+ return QualType();
+ }
if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(),
RHS->getAs<ObjCObjectPointerType>()))
return LHS;
return QualType();
- }
+ }
}
return QualType();
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index f568d1cdd45e..6c9a45ef6c44 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -430,7 +430,10 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
for (; I!=End; ++I)
QualName += *I + "::";
- QualName += getNameAsString();
+ if (getDeclName())
+ QualName += getNameAsString();
+ else
+ QualName += "<anonymous>";
return QualName;
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 7d1033d4f15f..ab6b9e1f45ad 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -743,7 +743,10 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
}
ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const {
- return getClassInterface()->FindCategoryDeclaration(getIdentifier());
+ // The class interface might be NULL if we are working with invalid code.
+ if (const ObjCInterfaceDecl *ID = getClassInterface())
+ return ID->FindCategoryDeclaration(getIdentifier());
+ return 0;
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 1b3202dd4282..6a71e925d9b3 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -227,7 +227,12 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
llvm::raw_svector_ostream Out(Name);
Out << (MD->isInstanceMethod() ? '-' : '+');
Out << '[';
- Out << MD->getClassInterface()->getNameAsString();
+
+ // For incorrect code, there might not be an ObjCInterfaceDecl. Do
+ // a null check to avoid a crash.
+ if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
+ Out << ID->getNameAsString();
+
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) {
Out << '(';
@@ -1104,11 +1109,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (m->isArrow())
return LV_Valid;
Expr *BaseExp = m->getBase();
- if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass)
+ if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass ||
+ BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass)
return LV_SubObjCPropertySetting;
return
- (BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass) ?
- LV_SubObjCPropertyGetterSetting : BaseExp->isLvalue(Ctx);
+ BaseExp->isLvalue(Ctx);
}
case UnaryOperatorClass:
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
@@ -1324,8 +1329,6 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
return MLV_InvalidExpression;
case LV_MemberFunction: return MLV_MemberFunction;
case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
- case LV_SubObjCPropertyGetterSetting:
- return MLV_SubObjCPropertyGetterSetting;
case LV_ClassTemporary:
return MLV_ClassTemporary;
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index e03669246e88..eeeeb5c836b8 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -406,27 +406,34 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (!EvaluatePointer(PExp, ResultLValue, Info))
return APValue();
- llvm::APSInt AdditionalOffset(32);
+ llvm::APSInt AdditionalOffset;
if (!EvaluateInteger(IExp, AdditionalOffset, Info))
return APValue();
- QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType();
- CharUnits SizeOfPointee;
+ // Compute the new offset in the appropriate width.
+
+ QualType PointeeType =
+ PExp->getType()->getAs<PointerType>()->getPointeeType();
+ llvm::APSInt SizeOfPointee(AdditionalOffset);
// Explicitly handle GNU void* and function pointer arithmetic extensions.
if (PointeeType->isVoidType() || PointeeType->isFunctionType())
- SizeOfPointee = CharUnits::One();
+ SizeOfPointee = 1;
else
- SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType);
-
- CharUnits Offset = ResultLValue.getLValueOffset();
+ SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType).getQuantity();
+ llvm::APSInt Offset(AdditionalOffset);
+ Offset = ResultLValue.getLValueOffset().getQuantity();
if (E->getOpcode() == BinaryOperator::Add)
- Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee;
+ Offset += AdditionalOffset * SizeOfPointee;
else
- Offset -= AdditionalOffset.getLimitedValue() * SizeOfPointee;
+ Offset -= AdditionalOffset * SizeOfPointee;
- return APValue(ResultLValue.getLValueBase(), Offset);
+ // Sign extend prior to converting back to a char unit.
+ if (Offset.getBitWidth() < 64)
+ Offset.extend(64);
+ return APValue(ResultLValue.getLValueBase(),
+ CharUnits::fromQuantity(Offset.getLimitedValue()));
}
APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 09a61736d27e..0c4896decf85 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -412,10 +413,12 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
return;
std::string Buffer;
+ bool HasKindDecoration = false;
// We don't print tags unless this is an elaborated type.
// In C, we just assume every RecordType is an elaborated type.
if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) {
+ HasKindDecoration = true;
Buffer += D->getKindName();
Buffer += ' ';
}
@@ -425,15 +428,31 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
// this will always be empty.
AppendScope(D->getDeclContext(), Buffer);
- const char *ID;
if (const IdentifierInfo *II = D->getIdentifier())
- ID = II->getNameStart();
+ Buffer += II->getNameStart();
else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) {
assert(Typedef->getIdentifier() && "Typedef without identifier?");
- ID = Typedef->getIdentifier()->getNameStart();
- } else
- ID = "<anonymous>";
- Buffer += ID;
+ Buffer += Typedef->getIdentifier()->getNameStart();
+ } else {
+ // Make an unambiguous representation for anonymous types, e.g.
+ // <anonymous enum at /usr/include/string.h:120:9>
+ llvm::raw_string_ostream OS(Buffer);
+ OS << "<anonymous";
+
+ // Suppress the redundant tag keyword if we just printed one.
+ // We don't have to worry about ElaboratedTypes here because you can't
+ // refer to an anonymous type with one.
+ if (!HasKindDecoration)
+ OS << " " << D->getKindName();
+
+ PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc(
+ D->getLocation());
+ OS << " at " << PLoc.getFilename()
+ << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn()
+ << '>';
+ OS.flush();
+ }
// If this is a class template specialization, print the template
// arguments.
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index 126d640364d0..7412b955606a 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -80,24 +80,24 @@ FullSourceLoc FullSourceLoc::getSpellingLoc() const {
return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr);
}
-unsigned FullSourceLoc::getInstantiationLineNumber() const {
+unsigned FullSourceLoc::getInstantiationLineNumber(bool *Invalid) const {
assert(isValid());
- return SrcMgr->getInstantiationLineNumber(*this);
+ return SrcMgr->getInstantiationLineNumber(*this, Invalid);
}
-unsigned FullSourceLoc::getInstantiationColumnNumber() const {
+unsigned FullSourceLoc::getInstantiationColumnNumber(bool *Invalid) const {
assert(isValid());
- return SrcMgr->getInstantiationColumnNumber(*this);
+ return SrcMgr->getInstantiationColumnNumber(*this, Invalid);
}
-unsigned FullSourceLoc::getSpellingLineNumber() const {
+unsigned FullSourceLoc::getSpellingLineNumber(bool *Invalid) const {
assert(isValid());
- return SrcMgr->getSpellingLineNumber(*this);
+ return SrcMgr->getSpellingLineNumber(*this, Invalid);
}
-unsigned FullSourceLoc::getSpellingColumnNumber() const {
+unsigned FullSourceLoc::getSpellingColumnNumber(bool *Invalid) const {
assert(isValid());
- return SrcMgr->getSpellingColumnNumber(*this);
+ return SrcMgr->getSpellingColumnNumber(*this, Invalid);
}
bool FullSourceLoc::isInSystemHeader() const {
@@ -105,18 +105,18 @@ bool FullSourceLoc::isInSystemHeader() const {
return SrcMgr->isInSystemHeader(*this);
}
-const char *FullSourceLoc::getCharacterData() const {
+const char *FullSourceLoc::getCharacterData(bool *Invalid) const {
assert(isValid());
- return SrcMgr->getCharacterData(*this);
+ return SrcMgr->getCharacterData(*this, Invalid);
}
-const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const {
+const llvm::MemoryBuffer* FullSourceLoc::getBuffer(bool *Invalid) const {
assert(isValid());
- return SrcMgr->getBuffer(SrcMgr->getFileID(*this));
+ return SrcMgr->getBuffer(SrcMgr->getFileID(*this), Invalid);
}
-llvm::StringRef FullSourceLoc::getBufferData() const {
- return getBuffer()->getBuffer();
+llvm::StringRef FullSourceLoc::getBufferData(bool *Invalid) const {
+ return getBuffer(Invalid)->getBuffer();
}
std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const {
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 4007ccf2a61e..6def967c4cfa 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -32,14 +32,14 @@ using llvm::MemoryBuffer;
//===----------------------------------------------------------------------===//
ContentCache::~ContentCache() {
- delete Buffer;
+ delete Buffer.getPointer();
}
/// getSizeBytesMapped - Returns the number of bytes actually mapped for
/// this ContentCache. This can be 0 if the MemBuffer was not actually
/// instantiated.
unsigned ContentCache::getSizeBytesMapped() const {
- return Buffer ? Buffer->getBufferSize() : 0;
+ return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0;
}
/// getSize - Returns the size of the content encapsulated by this ContentCache.
@@ -47,15 +47,16 @@ unsigned ContentCache::getSizeBytesMapped() const {
/// scratch buffer. If the ContentCache encapsulates a source file, that
/// file is not lazily brought in from disk to satisfy this query.
unsigned ContentCache::getSize() const {
- return Buffer ? (unsigned) Buffer->getBufferSize()
- : (unsigned) Entry->getSize();
+ return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize()
+ : (unsigned) Entry->getSize();
}
void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
- assert(B != Buffer);
+ assert(B != Buffer.getPointer());
- delete Buffer;
- Buffer = B;
+ delete Buffer.getPointer();
+ Buffer.setPointer(B);
+ Buffer.setInt(false);
}
const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
@@ -64,12 +65,13 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
*Invalid = false;
// Lazily create the Buffer for ContentCaches that wrap files.
- if (!Buffer && Entry) {
+ if (!Buffer.getPointer() && Entry) {
std::string ErrorStr;
struct stat FileInfo;
- Buffer = MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
- Entry->getSize(), &FileInfo);
-
+ Buffer.setPointer(MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
+ Entry->getSize(), &FileInfo));
+ Buffer.setInt(false);
+
// If we were unable to open the file, then we are in an inconsistent
// situation where the content cache referenced a file which no longer
// exists. Most likely, we were using a stat cache with an invalid entry but
@@ -80,34 +82,31 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
// currently handle returning a null entry here. Ideally we should detect
// that we are in an inconsistent situation and error out as quickly as
// possible.
- if (!Buffer) {
+ if (!Buffer.getPointer()) {
const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
- Buffer = MemoryBuffer::getNewMemBuffer(Entry->getSize(), "<invalid>");
- char *Ptr = const_cast<char*>(Buffer->getBufferStart());
+ Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(),
+ "<invalid>"));
+ char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
Diag.Report(diag::err_cannot_open_file)
<< Entry->getName() << ErrorStr;
- if (Invalid)
- *Invalid = true;
- } else {
- // Check that the file's size and modification time is the same as
- // in the file entry (which may have come from a stat cache).
- if (FileInfo.st_size != Entry->getSize()) {
- Diag.Report(diag::err_file_size_changed)
- << Entry->getName() << (unsigned)Entry->getSize()
- << (unsigned)FileInfo.st_size;
- if (Invalid)
- *Invalid = true;
- } else if (FileInfo.st_mtime != Entry->getModificationTime()) {
- Diag.Report(diag::err_file_modified) << Entry->getName();
- if (Invalid)
- *Invalid = true;
- }
+ Buffer.setInt(true);
+ } else if (FileInfo.st_size != Entry->getSize() ||
+ FileInfo.st_mtime != Entry->getModificationTime() ||
+ FileInfo.st_ino != Entry->getInode()) {
+ // Check that the file's size, modification time, and inode are
+ // the same as in the file entry (which may have come from a
+ // stat cache).
+ Diag.Report(diag::err_file_modified) << Entry->getName();
+ Buffer.setInt(true);
}
}
- return Buffer;
+ if (Invalid)
+ *Invalid = Buffer.getInt();
+
+ return Buffer.getPointer();
}
unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) {
@@ -412,7 +411,7 @@ FileID SourceManager::createFileID(const ContentCache *File,
= SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter));
SLocEntryLoaded[PreallocatedID] = true;
FileID FID = FileID::get(PreallocatedID);
- return LastFileIDLookup = FID;
+ return FID;
}
SLocEntryTable.push_back(SLocEntry::get(NextOffset,
@@ -475,15 +474,14 @@ bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
}
llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
+ bool MyInvalid = false;
+ const llvm::MemoryBuffer *Buf = getBuffer(FID, &MyInvalid);
if (Invalid)
- *Invalid = false;
-
- const llvm::MemoryBuffer *Buf = getBuffer(FID);
- if (!Buf) {
- if (*Invalid)
- *Invalid = true;
+ *Invalid = MyInvalid;
+
+ if (MyInvalid)
return "";
- }
+
return Buf->getBuffer();
}
diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 10136f3fc45b..7c5399113df7 100644
--- a/lib/Checker/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -72,7 +72,9 @@ public:
/// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values.
/// It updatees the GRState object in place with the values removed.
- Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
+ Store RemoveDeadBindings(Store store, Stmt* Loc,
+ const StackFrameContext *LCtx,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
void iterBindings(Store store, BindingsHandler& f);
@@ -250,6 +252,7 @@ Store BasicStoreManager::Remove(Store store, Loc loc) {
}
Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
+ const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp
index 0cf593b26009..7272b348581b 100644
--- a/lib/Checker/BugReporter.cpp
+++ b/lib/Checker/BugReporter.cpp
@@ -36,6 +36,23 @@ BugReporterContext::~BugReporterContext() {
if ((*I)->isOwnedByReporterContext()) delete *I;
}
+void BugReporterContext::addVisitor(BugReporterVisitor* visitor) {
+ if (!visitor)
+ return;
+
+ llvm::FoldingSetNodeID ID;
+ visitor->Profile(ID);
+ void *InsertPos;
+
+ if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
+ delete visitor;
+ return;
+ }
+
+ CallbacksSet.InsertNode(visitor, InsertPos);
+ Callbacks = F.Add(visitor, Callbacks);
+}
+
//===----------------------------------------------------------------------===//
// Helper routines for walking the ExplodedGraph and fetching statements.
//===----------------------------------------------------------------------===//
@@ -1613,7 +1630,9 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
else
return;
+ // Register node visitors.
R->registerInitialVisitors(PDB, N);
+ bugreporter::registerNilReceiverVisitor(PDB);
switch (PDB.getGenerationScheme()) {
case PathDiagnosticClient::Extensive:
diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp
index 6cf41b14dc5a..1d6994b94b4b 100644
--- a/lib/Checker/BugReporterVisitors.cpp
+++ b/lib/Checker/BugReporterVisitors.cpp
@@ -92,6 +92,13 @@ public:
FindLastStoreBRVisitor(SVal v, const MemRegion *r)
: R(r), V(v), satisfied(false), StoreSite(0) {}
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int tag = 0;
+ ID.AddPointer(&tag);
+ ID.AddPointer(R);
+ ID.Add(V);
+ }
+
PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext& BRC) {
@@ -129,8 +136,8 @@ public:
return NULL;
satisfied = true;
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
+ llvm::SmallString<256> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
@@ -239,6 +246,13 @@ public:
TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
: Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int tag = 0;
+ ID.AddPointer(&tag);
+ ID.AddBoolean(Assumption);
+ ID.Add(Constraint);
+ }
+
PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext& BRC) {
@@ -365,3 +379,52 @@ void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC,
BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
}
+
+
+namespace {
+class NilReceiverVisitor : public BugReporterVisitor {
+public:
+ NilReceiverVisitor() {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int x = 0;
+ ID.AddPointer(&x);
+ }
+
+ PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext& BRC) {
+
+ const PostStmt *P = N->getLocationAs<PostStmt>();
+ if (!P)
+ return 0;
+ const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
+ if (!ME)
+ return 0;
+ const Expr *Receiver = ME->getReceiver();
+ if (!Receiver)
+ return 0;
+ const GRState *state = N->getState();
+ const SVal &V = state->getSVal(Receiver);
+ const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
+ if (!DV)
+ return 0;
+ state = state->Assume(*DV, true);
+ if (state)
+ return 0;
+
+ // The receiver was nil, and hence the method was skipped.
+ // Register a BugReporterVisitor to issue a message telling us how
+ // the receiver was null.
+ bugreporter::registerTrackNullOrUndefValue(BRC, Receiver, N);
+ // Issue a message saying that the method was skipped.
+ PathDiagnosticLocation L(Receiver, BRC.getSourceManager());
+ return new PathDiagnosticEventPiece(L, "No method actually called "
+ "because the receiver is nil");
+ }
+};
+} // end anonymous namespace
+
+void clang::bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) {
+ BRC.addVisitor(new NilReceiverVisitor());
+}
diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp
index 9013c3818b0c..32cf7534c8f6 100644
--- a/lib/Checker/CallAndMessageChecker.cpp
+++ b/lib/Checker/CallAndMessageChecker.cpp
@@ -24,7 +24,7 @@ namespace {
class CallAndMessageChecker
: public CheckerVisitor<CallAndMessageChecker> {
BugType *BT_call_null;
- BugType *BT_call_undef;
+ BugType *BT_call_undef;
BugType *BT_call_arg;
BugType *BT_msg_undef;
BugType *BT_msg_arg;
@@ -44,12 +44,20 @@ public:
bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
private:
+ bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
+ const char *BT_desc, BugType *&BT);
+
void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
ExplodedNode *N);
-
+
void HandleNilReceiver(CheckerContext &C, const GRState *state,
- const ObjCMessageExpr *ME);
+ const ObjCMessageExpr *ME);
+
+ void LazyInit_BT(const char *desc, BugType *&BT) {
+ if (!BT)
+ BT = new BuiltinBug(desc);
+ }
};
} // end anonymous namespace
@@ -62,19 +70,127 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
ExplodedNode *N = C.GenerateSink();
if (!N)
return;
-
+
EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetCalleeExpr(N));
C.EmitReport(R);
}
-void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
+bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
+ const Expr *Ex,
+ const char *BT_desc,
+ BugType *&BT) {
+
+ const SVal &V = C.getState()->getSVal(Ex);
+
+ if (V.isUndef()) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ LazyInit_BT(BT_desc, BT);
+
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ R->addRange(Ex->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ C.EmitReport(R);
+ }
+ return true;
+ }
+
+ if (const nonloc::LazyCompoundVal *LV =
+ dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+ class FindUninitializedField {
+ public:
+ llvm::SmallVector<const FieldDecl *, 10> FieldChain;
+ private:
+ ASTContext &C;
+ StoreManager &StoreMgr;
+ MemRegionManager &MrMgr;
+ Store store;
+ public:
+ FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
+ MemRegionManager &mrMgr, Store s)
+ : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
+
+ bool Find(const TypedRegion *R) {
+ QualType T = R->getValueType(C);
+ if (const RecordType *RT = T->getAsStructureType()) {
+ const RecordDecl *RD = RT->getDecl()->getDefinition();
+ assert(RD && "Referred record has no definition");
+ for (RecordDecl::field_iterator I =
+ RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
+ const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
+ FieldChain.push_back(*I);
+ T = (*I)->getType();
+ if (T->getAsStructureType()) {
+ if (Find(FR))
+ return true;
+ }
+ else {
+ const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
+ if (V.isUndef())
+ return true;
+ }
+ FieldChain.pop_back();
+ }
+ }
+
+ return false;
+ }
+ };
+
+ const LazyCompoundValData *D = LV->getCVData();
+ FindUninitializedField F(C.getASTContext(),
+ C.getState()->getStateManager().getStoreManager(),
+ C.getValueManager().getRegionManager(),
+ D->getStore());
+
+ if (F.Find(D->getRegion())) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ LazyInit_BT(BT_desc, BT);
+ llvm::SmallString<512> Str;
+ llvm::raw_svector_ostream os(Str);
+ os << "Passed-by-value struct argument contains uninitialized data";
+
+ if (F.FieldChain.size() == 1)
+ os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString()
+ << "')";
+ else {
+ os << " (e.g., via the field chain: '";
+ bool first = true;
+ for (llvm::SmallVectorImpl<const FieldDecl *>::iterator
+ DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
+ if (first)
+ first = false;
+ else
+ os << '.';
+ os << (*DI)->getNameAsString();
+ }
+ os << "')";
+ }
+
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
+ R->addRange(Ex->getSourceRange());
+
+ // FIXME: enhance track back for uninitialized value for arbitrary
+ // memregions
+ C.EmitReport(R);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
const CallExpr *CE){
-
+
const Expr *Callee = CE->getCallee()->IgnoreParens();
SVal L = C.getState()->getSVal(Callee);
-
+
if (L.isUndef()) {
if (!BT_call_undef)
BT_call_undef =
@@ -82,31 +198,20 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
EmitBadCall(BT_call_undef, C, CE);
return;
}
-
+
if (isa<loc::ConcreteInt>(L)) {
if (!BT_call_null)
BT_call_null =
new BuiltinBug("Called function pointer is null (null dereference)");
EmitBadCall(BT_call_null, C, CE);
- }
-
- for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I) {
- if (C.getState()->getSVal(*I).isUndef()) {
- if (ExplodedNode *N = C.GenerateSink()) {
- if (!BT_call_arg)
- BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
- " is undefined");
- // Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
- BT_call_arg->getName(), N);
- R->addRange((*I)->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
- C.EmitReport(R);
- return;
- }
- }
}
+
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+ I != E; ++I)
+ if (PreVisitProcessArg(C, *I,
+ "Pass-by-value argument in function call is"
+ " undefined", BT_call_arg))
+ return;
}
void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
@@ -132,23 +237,11 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
// Check for any arguments that are uninitialized/undefined.
for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
- E = ME->arg_end(); I != E; ++I) {
- if (state->getSVal(*I).isUndef()) {
- if (ExplodedNode *N = C.GenerateSink()) {
- if (!BT_msg_arg)
- BT_msg_arg =
- new BuiltinBug("Pass-by-value argument in message expression"
- " is undefined");
- // Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
- BT_msg_arg->getName(), N);
- R->addRange((*I)->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
- C.EmitReport(R);
+ E = ME->arg_end(); I != E; ++I)
+ if (PreVisitProcessArg(C, *I,
+ "Pass-by-value argument in message expression "
+ "is undefined", BT_msg_arg))
return;
- }
- }
- }
}
bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
@@ -160,24 +253,24 @@ bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
const ObjCMessageExpr *ME,
ExplodedNode *N) {
-
+
if (!BT_msg_ret)
BT_msg_ret =
new BuiltinBug("Receiver in message expression is "
"'nil' and returns a garbage value");
-
+
llvm::SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The receiver of message '" << ME->getSelector().getAsString()
<< "' is nil and returns a value of type '"
<< ME->getType().getAsString() << "' that will be garbage";
-
+
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
const Expr *receiver = ME->getReceiver();
report->addRange(receiver->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
receiver);
- C.EmitReport(report);
+ C.EmitReport(report);
}
static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
@@ -188,11 +281,11 @@ static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
const GRState *state,
const ObjCMessageExpr *ME) {
-
+
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
QualType RetTy = ME->getType();
-
+
ASTContext &Ctx = C.getASTContext();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
@@ -216,7 +309,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
if (CanRetTy != Ctx.VoidTy &&
C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
// Compute: sizeof(void *) and sizeof(return type)
- const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
+ const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
if (voidPtrSize < returnTypeSize &&
@@ -247,6 +340,6 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
C.GenerateNode(state->BindExpr(ME, V));
return;
}
-
+
C.addTransition(state);
}
diff --git a/lib/Checker/CheckDeadStores.cpp b/lib/Checker/CheckDeadStores.cpp
index 31f9390e6228..d6ea187957ce 100644
--- a/lib/Checker/CheckDeadStores.cpp
+++ b/lib/Checker/CheckDeadStores.cpp
@@ -220,16 +220,25 @@ public:
if (E->isConstantInitializer(Ctx))
return;
- // Special case: check for initializations from constant
- // variables.
- //
- // e.g. extern const int MyConstant;
- // int x = MyConstant;
- //
if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
- if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ // Special case: check for initialization from constant
+ // variables.
+ //
+ // e.g. extern const int MyConstant;
+ // int x = MyConstant;
+ //
if (VD->hasGlobalStorage() &&
- VD->getType().isConstQualified()) return;
+ VD->getType().isConstQualified())
+ return;
+ // Special case: check for initialization from scalar
+ // parameters. This is often a form of defensive
+ // programming. Non-scalars are still an error since
+ // because it more likely represents an actual algorithmic
+ // bug.
+ if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
+ return;
+ }
Report(V, DeadInit, V->getLocation(), E->getSourceRange());
}
diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp
index 07a54fb48736..2af9ffa4a4d9 100644
--- a/lib/Checker/FlatStore.cpp
+++ b/lib/Checker/FlatStore.cpp
@@ -44,7 +44,9 @@ public:
}
SVal ArrayToPointer(Loc Array);
- Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
+ Store RemoveDeadBindings(Store store, Stmt* Loc,
+ const StackFrameContext *LCtx,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){
return store;
}
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index e64ba9446d89..3ace552adcb2 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -481,7 +481,9 @@ void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
SymbolReaper SymReaper(BasePred->getLocationContext(), SymMgr);
CleanedState = AMgr.shouldPurgeDead()
- ? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, SymReaper)
+ ? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt,
+ BasePred->getLocationContext()->getCurrentStackFrame(),
+ SymReaper)
: EntryNode->getState();
// Process any special transfer function for dead symbols.
diff --git a/lib/Checker/GRState.cpp b/lib/Checker/GRState.cpp
index 97ede1d480f9..2defbcd93c01 100644
--- a/lib/Checker/GRState.cpp
+++ b/lib/Checker/GRState.cpp
@@ -35,6 +35,7 @@ GRStateManager::~GRStateManager() {
const GRState*
GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
+ const StackFrameContext *LCtx,
SymbolReaper& SymReaper) {
// This code essentially performs a "mark-and-sweep" of the VariableBindings.
@@ -50,7 +51,7 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
state, RegionRoots);
// Clean up the store.
- NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, SymReaper,
+ NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, LCtx, SymReaper,
RegionRoots);
return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState),
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index 307ef7880388..c2b702acad9a 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -354,7 +354,9 @@ public: // Part of public interface to class.
/// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed.
- Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
+ Store RemoveDeadBindings(Store store, Stmt* Loc,
+ const StackFrameContext *LCtx,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
const GRState *EnterStackFrame(const GRState *state,
@@ -1678,12 +1680,14 @@ class RemoveDeadBindingsWorker :
llvm::SmallVector<const SymbolicRegion*, 12> Postponed;
SymbolReaper &SymReaper;
Stmt *Loc;
+ const StackFrameContext *CurrentLCtx;
+
public:
RemoveDeadBindingsWorker(RegionStoreManager &rm, GRStateManager &stateMgr,
RegionBindings b, SymbolReaper &symReaper,
- Stmt *loc)
+ Stmt *loc, const StackFrameContext *LCtx)
: ClusterAnalysis<RemoveDeadBindingsWorker>(rm, stateMgr, b),
- SymReaper(symReaper), Loc(loc) {}
+ SymReaper(symReaper), Loc(loc), CurrentLCtx(LCtx) {}
// Called by ClusterAnalysis.
void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C);
@@ -1713,6 +1717,15 @@ void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
return;
}
+
+ // CXXThisRegion in the current or parent location context is live.
+ if (const CXXThisRegion *TR = dyn_cast<CXXThisRegion>(baseR)) {
+ const StackArgumentsSpaceRegion *StackReg =
+ cast<StackArgumentsSpaceRegion>(TR->getSuperRegion());
+ const StackFrameContext *RegCtx = StackReg->getStackFrame();
+ if (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx))
+ AddToWorkList(TR, C);
+ }
}
void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
@@ -1799,11 +1812,12 @@ bool RemoveDeadBindingsWorker::UpdatePostponed() {
}
Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
+ const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
RegionBindings B = GetRegionBindings(store);
- RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc);
+ RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc, LCtx);
W.GenerateClusters();
// Enqueue the region roots onto the worklist.
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 706e4411fc79..419ed734e83e 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -25,17 +25,47 @@ using namespace clang;
using namespace CodeGen;
using namespace llvm;
+static void EmitMemoryBarrier(CodeGenFunction &CGF,
+ bool LoadLoad, bool LoadStore,
+ bool StoreLoad, bool StoreStore,
+ bool Device) {
+ Value *True = llvm::ConstantInt::getTrue(CGF.getLLVMContext());
+ Value *False = llvm::ConstantInt::getFalse(CGF.getLLVMContext());
+ Value *C[5] = { LoadLoad ? True : False,
+ LoadStore ? True : False,
+ StoreLoad ? True : False,
+ StoreStore ? True : False,
+ Device ? True : False };
+ CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::memory_barrier),
+ C, C + 5);
+}
+
+// The atomic builtins are also full memory barriers. This is a utility for
+// wrapping a call to the builtins with memory barriers.
+static Value *EmitCallWithBarrier(CodeGenFunction &CGF, Value *Fn,
+ Value **ArgBegin, Value **ArgEnd) {
+ // FIXME: We need a target hook for whether this applies to device memory or
+ // not.
+ bool Device = true;
+
+ // Create barriers both before and after the call.
+ EmitMemoryBarrier(CGF, true, true, true, true, Device);
+ Value *Result = CGF.Builder.CreateCall(Fn, ArgBegin, ArgEnd);
+ EmitMemoryBarrier(CGF, true, true, true, true, Device);
+ return Result;
+}
+
/// Utility to insert an atomic instruction based on Instrinsic::ID
/// and the expression node.
-static RValue EmitBinaryAtomic(CodeGenFunction& CGF,
+static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
Intrinsic::ID Id, const CallExpr *E) {
+ Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
+ CGF.EmitScalarExpr(E->getArg(1)) };
const llvm::Type *ResType[2];
ResType[0] = CGF.ConvertType(E->getType());
ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
- return RValue::get(CGF.Builder.CreateCall2(AtomF,
- CGF.EmitScalarExpr(E->getArg(0)),
- CGF.EmitScalarExpr(E->getArg(1))));
+ return RValue::get(EmitCallWithBarrier(CGF, AtomF, Args, Args + 2));
}
/// Utility to insert an atomic instruction based Instrinsic::ID and
@@ -48,15 +78,14 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF,
ResType[0] = CGF.ConvertType(E->getType());
ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
- Value *Ptr = CGF.EmitScalarExpr(E->getArg(0));
- Value *Operand = CGF.EmitScalarExpr(E->getArg(1));
- Value *Result = CGF.Builder.CreateCall2(AtomF, Ptr, Operand);
+ Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
+ CGF.EmitScalarExpr(E->getArg(1)) };
+ Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2);
if (Id == Intrinsic::atomic_load_nand)
Result = CGF.Builder.CreateNot(Result);
-
- return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Operand));
+ return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Args[1]));
}
static llvm::ConstantInt *getInt32(llvm::LLVMContext &Context, int32_t Value) {
@@ -585,33 +614,31 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_val_compare_and_swap_2:
case Builtin::BI__sync_val_compare_and_swap_4:
case Builtin::BI__sync_val_compare_and_swap_8:
- case Builtin::BI__sync_val_compare_and_swap_16:
- {
+ case Builtin::BI__sync_val_compare_and_swap_16: {
const llvm::Type *ResType[2];
ResType[0]= ConvertType(E->getType());
ResType[1] = ConvertType(E->getArg(0)->getType());
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
- return RValue::get(Builder.CreateCall3(AtomF,
- EmitScalarExpr(E->getArg(0)),
- EmitScalarExpr(E->getArg(1)),
- EmitScalarExpr(E->getArg(2))));
+ Value *Args[3] = { EmitScalarExpr(E->getArg(0)),
+ EmitScalarExpr(E->getArg(1)),
+ EmitScalarExpr(E->getArg(2)) };
+ return RValue::get(EmitCallWithBarrier(*this, AtomF, Args, Args + 3));
}
case Builtin::BI__sync_bool_compare_and_swap_1:
case Builtin::BI__sync_bool_compare_and_swap_2:
case Builtin::BI__sync_bool_compare_and_swap_4:
case Builtin::BI__sync_bool_compare_and_swap_8:
- case Builtin::BI__sync_bool_compare_and_swap_16:
- {
+ case Builtin::BI__sync_bool_compare_and_swap_16: {
const llvm::Type *ResType[2];
ResType[0]= ConvertType(E->getArg(1)->getType());
ResType[1] = llvm::PointerType::getUnqual(ResType[0]);
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
Value *OldVal = EmitScalarExpr(E->getArg(1));
- Value *PrevVal = Builder.CreateCall3(AtomF,
- EmitScalarExpr(E->getArg(0)),
- OldVal,
- EmitScalarExpr(E->getArg(2)));
+ Value *Args[3] = { EmitScalarExpr(E->getArg(0)),
+ OldVal,
+ EmitScalarExpr(E->getArg(2)) };
+ Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args, Args + 3);
Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal);
// zext bool to int.
return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType())));
@@ -623,6 +650,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_lock_test_and_set_8:
case Builtin::BI__sync_lock_test_and_set_16:
return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E);
+
case Builtin::BI__sync_lock_release_1:
case Builtin::BI__sync_lock_release_2:
case Builtin::BI__sync_lock_release_4:
@@ -638,10 +666,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI__sync_synchronize: {
- Value *C[5];
- C[0] = C[1] = C[2] = C[3] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 1);
- C[4] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0);
- Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5);
+ // We assume like gcc appears to, that this only applies to cached memory.
+ EmitMemoryBarrier(*this, true, true, true, true, false);
return RValue::get(0);
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 7752cf79a28d..b88001c81e9f 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -165,19 +165,21 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule());
// Switch any previous uses to the alias.
- const char *MangledName = getMangledName(AliasDecl);
- llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
+ MangleBuffer MangledName;
+ getMangledName(MangledName, AliasDecl);
+ llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
assert(Entry->isDeclaration() && "definition already exists for alias");
assert(Entry->getType() == AliasType &&
"declaration exists with different type");
+ Alias->takeName(Entry);
Entry->replaceAllUsesWith(Alias);
Entry->eraseFromParent();
+ } else {
+ Alias->setName(MangledName.getString());
}
- Entry = Alias;
// Finally, set up the alias with its proper name and attributes.
- Alias->setName(MangledName);
SetCommonAttributes(AliasDecl.getDecl(), Alias);
return false;
@@ -214,8 +216,9 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
llvm::GlobalValue *
CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
CXXCtorType Type) {
- const char *Name = getMangledCXXCtorName(D, Type);
- if (llvm::GlobalValue *V = GlobalDeclMap[Name])
+ MangleBuffer Name;
+ getMangledCXXCtorName(Name, D, Type);
+ if (llvm::GlobalValue *V = GetGlobalValue(Name))
return V;
const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
@@ -226,13 +229,10 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type)));
}
-const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
- CXXCtorType Type) {
- llvm::SmallString<256> Name;
- getMangleContext().mangleCXXCtor(D, Type, Name);
-
- Name += '\0';
- return UniqueMangledName(Name.begin(), Name.end());
+void CodeGenModule::getMangledCXXCtorName(MangleBuffer &Name,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type) {
+ getMangleContext().mangleCXXCtor(D, Type, Name.getBuffer());
}
void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
@@ -279,8 +279,9 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
llvm::GlobalValue *
CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type) {
- const char *Name = getMangledCXXDtorName(D, Type);
- if (llvm::GlobalValue *V = GlobalDeclMap[Name])
+ MangleBuffer Name;
+ getMangledCXXDtorName(Name, D, Type);
+ if (llvm::GlobalValue *V = GetGlobalValue(Name))
return V;
const llvm::FunctionType *FTy =
@@ -290,13 +291,10 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type)));
}
-const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D,
- CXXDtorType Type) {
- llvm::SmallString<256> Name;
- getMangleContext().mangleCXXDtor(D, Type, Name);
-
- Name += '\0';
- return UniqueMangledName(Name.begin(), Name.end());
+void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name,
+ const CXXDestructorDecl *D,
+ CXXDtorType Type) {
+ getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer());
}
llvm::Constant *
@@ -470,12 +468,10 @@ CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
OutName);
else
getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
- OutName += '\0';
- const char* Name = UniqueMangledName(OutName.begin(), OutName.end());
// Get function for mangled name
const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
- return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
+ return GetOrCreateLLVMFunction(OutName, Ty, GlobalDecl());
}
llvm::Constant *
@@ -484,10 +480,8 @@ CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD,
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
// Compute mangled name
- llvm::SmallString<256> OutName;
- getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName);
- OutName += '\0';
- const char* Name = UniqueMangledName(OutName.begin(), OutName.end());
+ llvm::SmallString<256> Name;
+ getMangleContext().mangleCovariantThunk(MD, Adjustment, Name);
// Get function for mangled name
const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
@@ -528,9 +522,6 @@ void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) {
llvm::Constant *SubExpr =
cast<llvm::ConstantExpr>(FnConst)->getOperand(0);
llvm::Function *OldFn = cast<llvm::Function>(SubExpr);
- std::string Name = OldFn->getNameStr();
- GlobalDeclMap.erase(UniqueMangledName(Name.data(),
- Name.data() + Name.size() + 1));
llvm::Constant *NewFnConst;
if (!ReturnAdjustment.isEmpty())
NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj);
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 60aa4e784e6c..ad97d08a2bf7 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -104,12 +104,20 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
void CGDebugInfo::CreateCompileUnit() {
// Get absolute path name.
+ SourceManager &SM = CGM.getContext().getSourceManager();
std::string MainFileName = CGM.getCodeGenOpts().MainFileName;
if (MainFileName.empty())
MainFileName = "<unknown>";
+
llvm::sys::Path AbsFileName(MainFileName);
AbsFileName.makeAbsolute();
+ std::string MainFileDir;
+ if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID()))
+ MainFileDir = MainFile->getDir()->getName();
+ else
+ MainFileDir = AbsFileName.getDirname();
+
unsigned LangTag;
const LangOptions &LO = CGM.getLangOptions();
if (LO.CPlusPlus) {
@@ -138,7 +146,7 @@ void CGDebugInfo::CreateCompileUnit() {
// Create new compile unit.
TheCU = DebugFactory.CreateCompileUnit(
- LangTag, AbsFileName.getLast(), AbsFileName.getDirname(), Producer, true,
+ LangTag, AbsFileName.getLast(), MainFileDir, Producer, true,
LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
}
@@ -561,13 +569,13 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
llvm::StringRef MethodName = getFunctionName(Method);
- llvm::StringRef MethodLinkageName;
llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit);
// Since a single ctor/dtor corresponds to multiple functions, it doesn't
// make sense to give a single ctor/dtor a linkage name.
+ MangleBuffer MethodLinkageName;
if (!IsCtorOrDtor)
- MethodLinkageName = CGM.getMangledName(Method);
+ CGM.getMangledName(MethodLinkageName, Method);
SourceManager &SM = CGM.getContext().getSourceManager();
@@ -1299,7 +1307,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
CGBuilderTy &Builder) {
llvm::StringRef Name;
- llvm::StringRef LinkageName;
+ MangleBuffer LinkageName;
const Decl *D = GD.getDecl();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
@@ -1318,11 +1326,11 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
// Use mangled name as linkage name for c/c++ functions.
- LinkageName = CGM.getMangledName(GD);
+ CGM.getMangledName(LinkageName, GD);
} else {
// Use llvm function name as linkage name.
Name = Fn->getName();
- LinkageName = Name;
+ LinkageName.setString(Name);
if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
}
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 1dc083f387ba..4eb95af8ff61 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -103,13 +103,18 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) {
static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
const char *Separator) {
CodeGenModule &CGM = CGF.CGM;
- if (CGF.getContext().getLangOptions().CPlusPlus)
- return CGM.getMangledName(&D);
+ if (CGF.getContext().getLangOptions().CPlusPlus) {
+ MangleBuffer Name;
+ CGM.getMangledName(Name, &D);
+ return Name.getString().str();
+ }
std::string ContextName;
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl))
- ContextName = CGM.getMangledName(FD);
- else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) {
+ MangleBuffer Name;
+ CGM.getMangledName(Name, FD);
+ ContextName = Name.getString().str();
+ } else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
ContextName = CGF.CurFn->getName();
else
// FIXME: What about in a block??
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 0de3b0be4b1a..40c18ca3c2a3 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
+#include "clang/CodeGen/CodeGenOptions.h"
using namespace clang;
using namespace CodeGen;
@@ -64,7 +65,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
} else
- DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
+ DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
}
@@ -92,6 +93,12 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
void
CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Constant *DeclPtr) {
+ // Generate a global destructor entry if not using __cxa_atexit.
+ if (!CGM.getCodeGenOpts().CXAAtExit) {
+ CGM.AddCXXDtorEntry(DtorFn, DeclPtr);
+ return;
+ }
+
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
@@ -150,10 +157,9 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
false);
// Create our global initialization function.
- // FIXME: Should this be tweakable by targets?
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
- "__cxx_global_initialization", &TheModule);
+ "_GLOBAL__I_a", &TheModule);
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
&CXXGlobalInits[0],
@@ -161,6 +167,28 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
AddGlobalCtor(Fn);
}
+void CodeGenModule::AddCXXDtorEntry(llvm::Constant *DtorFn,
+ llvm::Constant *Object) {
+ CXXGlobalDtors.push_back(std::make_pair(DtorFn, Object));
+}
+
+void CodeGenModule::EmitCXXGlobalDtorFunc() {
+ if (CXXGlobalDtors.empty())
+ return;
+
+ const llvm::FunctionType *FTy
+ = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ false);
+
+ // Create our global destructor function.
+ llvm::Function *Fn =
+ llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+ "_GLOBAL__D_a", &TheModule);
+
+ CodeGenFunction(*this).GenerateCXXGlobalDtorFunc(Fn, CXXGlobalDtors);
+ AddGlobalDtor(Fn);
+}
+
void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
@@ -184,6 +212,20 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
FinishFunction();
}
+void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
+ const std::vector<std::pair<llvm::Constant*, llvm::Constant*> >
+ &DtorsAndObjects) {
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
+ SourceLocation());
+
+ // Emit the dtors, in reverse order from construction.
+ for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i)
+ Builder.CreateCall(DtorsAndObjects[e - i - 1].first,
+ DtorsAndObjects[e - i - 1].second);
+
+ FinishFunction();
+}
+
static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) {
// int __cxa_guard_acquire(__int64_t *guard_object);
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 142cb811b059..1e1506683ddd 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -486,8 +486,6 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
- llvm::SmallVector<llvm::Value*, 8> Args;
- Args.clear();
SelectorArgs.push_back(Exc);
SelectorArgs.push_back(Personality);
@@ -584,12 +582,11 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even
// though we don't use the result.
- Args.clear();
- Args.push_back(Exc);
- Args.push_back(Personality);
- Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- 0));
- Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+ llvm::Value *Args[] = {
+ Exc, Personality,
+ llvm::ConstantInt::getNullValue(llvm::Type::getInt32Ty(VMContext))
+ };
+ Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
Builder.CreateStore(Exc, RethrowPtr);
EmitBranchThroughCleanup(FinallyRethrow);
@@ -600,7 +597,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
Builder.CreateInvoke(getEndCatchFn(*this),
Cont, TerminateHandler,
- Args.begin(), Args.begin());
+ &Args[0], &Args[0]);
EmitBlock(Cont);
if (Info.SwitchBlock)
EmitBlock(Info.SwitchBlock);
@@ -677,12 +674,8 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
// C string type. Used in lots of places.
PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
- llvm::SmallVector<llvm::Value*, 8> Args;
- Args.clear();
- Args.push_back(Exc);
- Args.push_back(Personality);
- Args.push_back(Null);
- CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+ llvm::Value *Args[] = { Exc, Personality, Null };
+ CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
CGF.EmitBlock(CleanupEntryBB);
@@ -731,12 +724,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even
// though we don't use the result.
- llvm::SmallVector<llvm::Value*, 8> Args;
- Args.push_back(Exc);
- Args.push_back(Personality);
- Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- 1));
- Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+ llvm::Value *Args[] = {
+ Exc, Personality,
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)
+ };
+ Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
llvm::CallInst *TerminateCall =
Builder.CreateCall(getTerminateFn(*this));
TerminateCall->setDoesNotReturn();
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 243635744ffb..119819b810be 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -1634,7 +1634,7 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCCategoryImplDecl *OCD =
dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
std::string CategoryName = OCD ? OCD->getNameAsString() : "";
- std::string ClassName = OMD->getClassInterface()->getNameAsString();
+ std::string ClassName = CD->getName();
std::string MethodName = OMD->getSelector().getAsString();
bool isClassMethod = !OMD->isInstanceMethod();
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 9bcf986af842..df30f479acc8 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
+#include <algorithm>
#include <cstdio>
using namespace clang;
@@ -1147,6 +1148,12 @@ private:
ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
+
+ friend bool operator==(const ReturnAdjustment &LHS,
+ const ReturnAdjustment &RHS) {
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
+ }
};
/// MethodInfo - Contains information about a method in a vtable.
@@ -1191,6 +1198,12 @@ private:
ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { }
bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; }
+
+ friend bool operator==(const ThisAdjustment &LHS,
+ const ThisAdjustment &RHS) {
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VCallOffsetOffset == RHS.VCallOffsetOffset;
+ }
};
/// ThunkInfo - The 'this' pointer adjustment as well as an optional return
@@ -1206,8 +1219,12 @@ private:
ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
: This(This), Return(Return) { }
-
- bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
+
+ friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ return LHS.This == RHS.This && LHS.Return == RHS.Return;
+ }
+
+ bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
};
typedef llvm::DenseMap<uint64_t, ThunkInfo> ThunksInfoMapTy;
@@ -1215,6 +1232,16 @@ private:
/// Thunks - The thunks by vtable index in the vtable currently being built.
ThunksInfoMapTy Thunks;
+ typedef llvm::DenseMap<const CXXMethodDecl *,
+ llvm::SmallVector<ThunkInfo, 1> > MethodThunksMapTy;
+
+ /// MethodThunks - A map that contains all the thunks needed for all methods
+ /// in the vtable currently being built.
+ MethodThunksMapTy MethodThunks;
+
+ /// AddThunk - Add a thunk for the given method.
+ void AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk);
+
/// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
/// part of the vtable we're currently building.
void ComputeThisAdjustments();
@@ -1330,6 +1357,20 @@ public:
void dumpLayout(llvm::raw_ostream&);
};
+void VtableBuilder::AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk) {
+ if (isBuildingConstructorVtable())
+ return;
+
+ llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD];
+
+ // Check if we have this thunk already.
+ if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
+ ThunksVector.end())
+ return;
+
+ ThunksVector.push_back(Thunk);
+}
+
/// OverridesMethodInBases - Checks whether whether this virtual member
/// function overrides a member function in any of the given bases.
/// Returns the overridden member function, or null if none was found.
@@ -1382,6 +1423,8 @@ void VtableBuilder::ComputeThisAdjustments() {
// Add an adjustment for the deleting destructor as well.
Thunks[VtableIndex + 1].This = ThisAdjustment;
}
+
+ AddThunk(Overrider.Method, Thunks[VtableIndex]);
}
/// Clear the method info map.
@@ -2182,20 +2225,25 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << '\n';
- if (!isBuildingConstructorVtable() && MostDerivedClass->getNumVBases()) {
- Out << "Virtual base offset offsets for '";
- Out << MostDerivedClass->getQualifiedNameAsString() << "'.\n";
-
+ if (isBuildingConstructorVtable())
+ return;
+
+ if (MostDerivedClass->getNumVBases()) {
// We store the virtual base class names and their offsets in a map to get
// a stable order.
- std::map<std::string, int64_t> ClassNamesAndOffsets;
+ std::map<std::string, int64_t> ClassNamesAndOffsets;
for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(),
E = VBaseOffsetOffsets.end(); I != E; ++I) {
std::string ClassName = I->first->getQualifiedNameAsString();
int64_t OffsetOffset = I->second;
ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset));
}
+
+ Out << "Virtual base offset offsets for '";
+ Out << MostDerivedClass->getQualifiedNameAsString() << "' (";
+ Out << ClassNamesAndOffsets.size();
+ Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n";
for (std::map<std::string, int64_t>::const_iterator I =
ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end();
@@ -2204,6 +2252,52 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << "\n";
}
+
+ if (!MethodThunks.empty()) {
+
+ // We store the method names in a map to get a stable order.
+ std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
+
+ for (MethodThunksMapTy::const_iterator I = MethodThunks.begin(),
+ E = MethodThunks.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ std::string MethodName =
+ PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
+ MD);
+
+ MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
+ }
+
+ for (std::map<std::string, const CXXMethodDecl *>::const_iterator I =
+ MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end();
+ I != E; ++I) {
+ const std::string &MethodName = I->first;
+ const CXXMethodDecl *MD = I->second;
+ const llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD];
+
+ Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
+ Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
+
+ for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
+ const ThunkInfo &Thunk = ThunksVector[I];
+
+ Out << llvm::format("%4d | ", I);
+
+ // If this function pointer has a 'this' pointer adjustment, dump it.
+ if (!Thunk.This.isEmpty()) {
+ Out << "this: ";
+ Out << Thunk.This.NonVirtual << " nv";
+
+ if (Thunk.This.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.VCallOffsetOffset;
+ Out << " v";
+ }
+ }
+
+ Out << '\n';
+ }
+ }
+ }
}
}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 88d641330009..bd12c4a87c29 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1231,6 +1231,12 @@ public:
llvm::Constant **Decls,
unsigned NumDecls);
+ /// GenerateCXXGlobalDtorFunc - Generates code for destroying global
+ /// variables.
+ void GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
+ const std::vector<std::pair<llvm::Constant*,
+ llvm::Constant*> > &DtorsAndObjects);
+
void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D);
void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f41db14f1a66..b4b5bbdb99aa 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -81,6 +81,7 @@ void CodeGenModule::createObjCRuntime() {
void CodeGenModule::Release() {
EmitDeferred();
EmitCXXGlobalInitFunc();
+ EmitCXXGlobalDtorFunc();
if (Runtime)
if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction())
AddGlobalCtor(ObjCInitFunction);
@@ -163,15 +164,15 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
}
}
-const char *CodeGenModule::getMangledName(const GlobalDecl &GD) {
+void CodeGenModule::getMangledName(MangleBuffer &Buffer, GlobalDecl GD) {
const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
if (const CXXConstructorDecl *D = dyn_cast<CXXConstructorDecl>(ND))
- return getMangledCXXCtorName(D, GD.getCtorType());
+ return getMangledCXXCtorName(Buffer, D, GD.getCtorType());
if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(ND))
- return getMangledCXXDtorName(D, GD.getDtorType());
+ return getMangledCXXDtorName(Buffer, D, GD.getDtorType());
- return getMangledName(ND);
+ return getMangledName(Buffer, ND);
}
/// \brief Retrieves the mangled name for the given declaration.
@@ -180,23 +181,19 @@ const char *CodeGenModule::getMangledName(const GlobalDecl &GD) {
/// const char* containing the mangled name. Otherwise, returns
/// the unmangled name.
///
-const char *CodeGenModule::getMangledName(const NamedDecl *ND) {
+void CodeGenModule::getMangledName(MangleBuffer &Buffer,
+ const NamedDecl *ND) {
if (!getMangleContext().shouldMangleDeclName(ND)) {
assert(ND->getIdentifier() && "Attempt to mangle unnamed decl.");
- return ND->getNameAsCString();
+ Buffer.setString(ND->getNameAsCString());
+ return;
}
- llvm::SmallString<256> Name;
- getMangleContext().mangleName(ND, Name);
- Name += '\0';
- return UniqueMangledName(Name.begin(), Name.end());
+ getMangleContext().mangleName(ND, Buffer.getBuffer());
}
-const char *CodeGenModule::UniqueMangledName(const char *NameStart,
- const char *NameEnd) {
- assert(*(NameEnd - 1) == '\0' && "Mangled name must be null terminated!");
-
- return MangledNames.GetOrCreateValue(NameStart, NameEnd).getKeyData();
+llvm::GlobalValue *CodeGenModule::GetGlobalValue(llvm::StringRef Name) {
+ return getModule().getNamedValue(Name);
}
/// AddGlobalCtor - Add a function to the list that will be called before
@@ -505,11 +502,12 @@ void CodeGenModule::EmitDeferred() {
GlobalDecl D = DeferredDeclsToEmit.back();
DeferredDeclsToEmit.pop_back();
- // The mangled name for the decl must have been emitted in GlobalDeclMap.
// Look it up to see if it was defined with a stronger definition (e.g. an
// extern inline function with a strong function redefinition). If so,
// just ignore the deferred decl.
- llvm::GlobalValue *CGRef = GlobalDeclMap[getMangledName(D)];
+ MangleBuffer Name;
+ getMangledName(Name, D);
+ llvm::GlobalValue *CGRef = GetGlobalValue(Name);
assert(CGRef && "Deferred decl wasn't referenced?");
if (!CGRef->isDeclaration())
@@ -644,18 +642,14 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType());
- // Unique the name through the identifier table.
- const char *AliaseeName =
- getContext().Idents.get(AA->getAliasee()).getNameStart();
-
// See if there is already something with the target's name in the module.
- llvm::GlobalValue *Entry = GlobalDeclMap[AliaseeName];
+ llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee());
llvm::Constant *Aliasee;
if (isa<llvm::FunctionType>(DeclTy))
- Aliasee = GetOrCreateLLVMFunction(AliaseeName, DeclTy, GlobalDecl());
+ Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl());
else
- Aliasee = GetOrCreateLLVMGlobal(AliaseeName,
+ Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
llvm::PointerType::getUnqual(DeclTy), 0);
if (!Entry) {
llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee);
@@ -676,7 +670,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// If this is an alias definition (which otherwise looks like a declaration)
// emit it now.
if (Global->hasAttr<AliasAttr>())
- return EmitAliasDefinition(Global);
+ return EmitAliasDefinition(GD);
// Ignore declarations, they will be emitted on their first use.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
@@ -696,8 +690,9 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
if (MayDeferGeneration(Global)) {
// If the value has already been used, add it directly to the
// DeferredDeclsToEmit list.
- const char *MangledName = getMangledName(GD);
- if (GlobalDeclMap.count(MangledName))
+ MangleBuffer MangledName;
+ getMangledName(MangledName, GD);
+ if (GetGlobalValue(MangledName))
DeferredDeclsToEmit.push_back(GD);
else {
// Otherwise, remember that we saw a deferred decl with this name. The
@@ -753,11 +748,12 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
///
/// If D is non-null, it specifies a decl that correspond to this. This is used
/// to set the attributes on the function when it is first created.
-llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
- const llvm::Type *Ty,
- GlobalDecl D) {
+llvm::Constant *
+CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
+ const llvm::Type *Ty,
+ GlobalDecl D) {
// Lookup the entry, lazily creating it if necessary.
- llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
+ llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
if (WeakRefReferences.count(Entry)) {
const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl());
@@ -786,17 +782,15 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
}
llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
llvm::Function::ExternalLinkage,
- "", &getModule());
- F->setName(MangledName);
+ MangledName, &getModule());
+ assert(F->getName() == MangledName && "name was uniqued!");
if (D.getDecl())
SetFunctionAttributes(D, F, IsIncompleteFunction);
- Entry = F;
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
// of the file.
- llvm::DenseMap<const char*, GlobalDecl>::iterator DDI =
- DeferredDecls.find(MangledName);
+ llvm::StringMap<GlobalDecl>::iterator DDI = DeferredDecls.find(MangledName);
if (DDI != DeferredDecls.end()) {
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
// list, and remove it from DeferredDecls (since we don't need it anymore).
@@ -839,16 +833,16 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
// If there was no specific requested type, just convert it now.
if (!Ty)
Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType());
- return GetOrCreateLLVMFunction(getMangledName(GD), Ty, GD);
+ MangleBuffer MangledName;
+ getMangledName(MangledName, GD);
+ return GetOrCreateLLVMFunction(MangledName, Ty, GD);
}
/// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name.
llvm::Constant *
CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
- const char *Name) {
- // Convert Name to be a uniqued string from the IdentifierInfo table.
- Name = getContext().Idents.get(Name).getNameStart();
+ llvm::StringRef Name) {
return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl());
}
@@ -870,11 +864,12 @@ static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) {
///
/// If D is non-null, it specifies a decl that correspond to this. This is used
/// to set the attributes on the global when it is first created.
-llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
- const llvm::PointerType*Ty,
- const VarDecl *D) {
+llvm::Constant *
+CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
+ const llvm::PointerType *Ty,
+ const VarDecl *D) {
// Lookup the entry, lazily creating it if necessary.
- llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
+ llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
if (WeakRefReferences.count(Entry)) {
if (D && !D->hasAttr<WeakAttr>())
@@ -893,8 +888,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
// of the file.
- llvm::DenseMap<const char*, GlobalDecl>::iterator DDI =
- DeferredDecls.find(MangledName);
+ llvm::StringMap<GlobalDecl>::iterator DDI = DeferredDecls.find(MangledName);
if (DDI != DeferredDecls.end()) {
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
// list, and remove it from DeferredDecls (since we don't need it anymore).
@@ -905,9 +899,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(getModule(), Ty->getElementType(), false,
llvm::GlobalValue::ExternalLinkage,
- 0, "", 0,
+ 0, MangledName, 0,
false, Ty->getAddressSpace());
- GV->setName(MangledName);
// Handle things which are present even on external declarations.
if (D) {
@@ -926,7 +919,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
GV->setThreadLocal(D->isThreadSpecified());
}
- return Entry = GV;
+ return GV;
}
@@ -943,16 +936,17 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
const llvm::PointerType *PTy =
llvm::PointerType::get(Ty, ASTTy.getAddressSpace());
- return GetOrCreateLLVMGlobal(getMangledName(D), PTy, D);
+
+ MangleBuffer MangledName;
+ getMangledName(MangledName, D);
+ return GetOrCreateLLVMGlobal(MangledName, PTy, D);
}
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *
CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty,
- const char *Name) {
- // Convert Name to be a uniqued string from the IdentifierInfo table.
- Name = getContext().Idents.get(Name).getNameStart();
+ llvm::StringRef Name) {
return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0);
}
@@ -963,8 +957,9 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
// If we have not seen a reference to this variable yet, place it
// into the deferred declarations table to be emitted if needed
// later.
- const char *MangledName = getMangledName(D);
- if (GlobalDeclMap.count(MangledName) == 0) {
+ MangleBuffer MangledName;
+ getMangledName(MangledName, D);
+ if (!GetGlobalValue(MangledName)) {
DeferredDecls[MangledName] = D;
return;
}
@@ -1133,12 +1128,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->getType()->getElementType() != InitType ||
GV->getType()->getAddressSpace() != ASTTy.getAddressSpace()) {
- // Remove the old entry from GlobalDeclMap so that we'll create a new one.
- GlobalDeclMap.erase(getMangledName(D));
+ // Move the old entry aside so that we'll create a new one.
+ Entry->setName(llvm::StringRef());
// Make a new global with the correct type, this is now guaranteed to work.
GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(D, InitType));
- GV->takeName(cast<llvm::GlobalValue>(Entry));
// Replace all uses of the old global with the new global
llvm::Constant *NewPtrForOldDecl =
@@ -1296,11 +1290,10 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
//
// This happens if there is a prototype for a function
// (e.g. "int f()") and then a definition of a different type
- // (e.g. "int f(int x)"). Start by making a new function of the
- // correct type, RAUW, then steal the name.
- GlobalDeclMap.erase(getMangledName(D));
+ // (e.g. "int f(int x)"). Move the old function aside so that it
+ // doesn't interfere with GetAddrOfFunction.
+ OldFn->setName(llvm::StringRef());
llvm::Function *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty));
- NewFn->takeName(OldFn);
// If this is an implementation of a function without a prototype, try to
// replace any existing uses of the function (which may be calls) with uses
@@ -1336,23 +1329,29 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
AddGlobalDtor(Fn, DA->getPriority());
}
-void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
+void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
+ const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
const AliasAttr *AA = D->getAttr<AliasAttr>();
assert(AA && "Not an alias?");
- const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
+ MangleBuffer MangledName;
+ getMangledName(MangledName, GD);
- // Unique the name through the identifier table.
- const char *AliaseeName =
- getContext().Idents.get(AA->getAliasee()).getNameStart();
+ // If there is a definition in the module, then it wins over the alias.
+ // This is dubious, but allow it to be safe. Just ignore the alias.
+ llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
+ if (Entry && !Entry->isDeclaration())
+ return;
+
+ const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
// Create a reference to the named value. This ensures that it is emitted
// if a deferred decl.
llvm::Constant *Aliasee;
if (isa<llvm::FunctionType>(DeclTy))
- Aliasee = GetOrCreateLLVMFunction(AliaseeName, DeclTy, GlobalDecl());
+ Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl());
else
- Aliasee = GetOrCreateLLVMGlobal(AliaseeName,
+ Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
llvm::PointerType::getUnqual(DeclTy), 0);
// Create the new alias itself, but don't set a name yet.
@@ -1361,18 +1360,9 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
llvm::Function::ExternalLinkage,
"", Aliasee, &getModule());
- // See if there is already something with the alias' name in the module.
- const char *MangledName = getMangledName(D);
- llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
-
- if (Entry && !Entry->isDeclaration()) {
- // If there is a definition in the module, then it wins over the alias.
- // This is dubious, but allow it to be safe. Just ignore the alias.
- GA->eraseFromParent();
- return;
- }
-
if (Entry) {
+ assert(Entry->isDeclaration());
+
// If there is a declaration in the module, then we had an extern followed
// by the alias, as in:
// extern int test6();
@@ -1380,16 +1370,15 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
// int test6() __attribute__((alias("test7")));
//
// Remove it and replace uses of it with the alias.
+ GA->takeName(Entry);
Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GA,
Entry->getType()));
Entry->eraseFromParent();
+ } else {
+ GA->setName(MangledName.getString());
}
- // Now we know that there is no conflict, set the name.
- Entry = GA;
- GA->setName(MangledName);
-
// Set attributes which are particular to an alias; this is a
// specialization of the attributes which may be set on a global
// variable/function.
@@ -1426,8 +1415,6 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
const llvm::FunctionType *Ty =
cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
- // Unique the name through the identifier table.
- Name = getContext().Idents.get(Name).getNameStart();
return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD));
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 9077adedd0b9..febb8560367b 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -73,7 +73,7 @@ namespace CodeGen {
class CodeGenFunction;
class CGDebugInfo;
class CGObjCRuntime;
-
+ class MangleBuffer;
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
@@ -103,38 +103,16 @@ class CodeGenModule : public BlockModule {
llvm::Function *MemMoveFn;
llvm::Function *MemSetFn;
- /// GlobalDeclMap - Mapping of decl names (represented as unique
- /// character pointers from either the identifier table or the set
- /// of mangled names) to global variables we have already
- /// emitted. Note that the entries in this map are the actual
- /// globals and therefore may not be of the same type as the decl,
- /// they should be bitcasted on retrieval. Also note that the
- /// globals are keyed on their source mangled name, not the global name
- /// (which may change with attributes such as asm-labels). The key
- /// to this map should be generated using getMangledName().
- ///
- /// Note that this map always lines up exactly with the contents of the LLVM
- /// IR symbol table, but this is quicker to query since it is doing uniqued
- /// pointer lookups instead of full string lookups.
- llvm::DenseMap<const char*, llvm::GlobalValue*> GlobalDeclMap;
-
// WeakRefReferences - A set of references that have only been seen via
// a weakref so far. This is used to remove the weak of the reference if we ever
// see a direct reference or a definition.
llvm::SmallPtrSet<llvm::GlobalValue*, 10> WeakRefReferences;
- /// \brief Contains the strings used for mangled names.
- ///
- /// FIXME: Eventually, this should map from the semantic/canonical
- /// declaration for each global entity to its mangled name (if it
- /// has one).
- llvm::StringSet<> MangledNames;
-
/// DeferredDecls - This contains all the decls which have definitions but
/// which are deferred for emission and therefore should only be output if
/// they are actually used. If a decl is in this, then it is known to have
- /// not been referenced yet. The key to this map is a uniqued mangled name.
- llvm::DenseMap<const char*, GlobalDecl> DeferredDecls;
+ /// not been referenced yet.
+ llvm::StringMap<GlobalDecl> DeferredDecls;
/// DeferredDeclsToEmit - This is a list of deferred decls which we have seen
/// that *are* actually referenced. These get code generated when the module
@@ -160,10 +138,14 @@ class CodeGenModule : public BlockModule {
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
llvm::StringMap<llvm::Constant*> ConstantStringMap;
- /// CXXGlobalInits - Variables with global initializers that need to run
+ /// CXXGlobalInits - Global variables with initializers that need to run
/// before main.
std::vector<llvm::Constant*> CXXGlobalInits;
+ /// CXXGlobalDtors - Global destructor functions and arguments that need to
+ /// run on termination.
+ std::vector<std::pair<llvm::Constant*,llvm::Constant*> > CXXGlobalDtors;
+
/// CFConstantStringClassRef - Cached reference to the class for constant
/// strings. This value has type int * but is actually an Obj-C class pointer.
llvm::Constant *CFConstantStringClassRef;
@@ -343,14 +325,18 @@ public:
void AddAnnotation(llvm::Constant *C) { Annotations.push_back(C); }
+ /// AddCXXDtorEntry - Add a destructor and object to add to the C++ global
+ /// destructor function.
+ void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object);
+
/// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name.
llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty,
- const char *Name);
+ llvm::StringRef Name);
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty,
- const char *Name);
+ llvm::StringRef Name);
void UpdateCompletedType(const TagDecl *TD) {
// Make sure that this type is translated.
@@ -422,13 +408,14 @@ public:
AttributeListType &PAL,
unsigned &CallingConv);
- const char *getMangledName(const GlobalDecl &D);
-
- const char *getMangledName(const NamedDecl *ND);
- const char *getMangledCXXCtorName(const CXXConstructorDecl *D,
- CXXCtorType Type);
- const char *getMangledCXXDtorName(const CXXDestructorDecl *D,
- CXXDtorType Type);
+ void getMangledName(MangleBuffer &Buffer, GlobalDecl D);
+ void getMangledName(MangleBuffer &Buffer, const NamedDecl *ND);
+ void getMangledCXXCtorName(MangleBuffer &Buffer,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type);
+ void getMangledCXXDtorName(MangleBuffer &Buffer,
+ const CXXDestructorDecl *D,
+ CXXDtorType Type);
void EmitTentativeDefinition(const VarDecl *D);
@@ -456,14 +443,12 @@ public:
std::vector<const CXXRecordDecl*> DeferredVtables;
private:
- /// UniqueMangledName - Unique a name by (if necessary) inserting it into the
- /// MangledNames string map.
- const char *UniqueMangledName(const char *NameStart, const char *NameEnd);
+ llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref);
- llvm::Constant *GetOrCreateLLVMFunction(const char *MangledName,
+ llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName,
const llvm::Type *Ty,
GlobalDecl D);
- llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName,
+ llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
const llvm::PointerType *PTy,
const VarDecl *D);
@@ -492,7 +477,7 @@ private:
void EmitGlobalFunctionDefinition(GlobalDecl GD);
void EmitGlobalVarDefinition(const VarDecl *D);
- void EmitAliasDefinition(const ValueDecl *D);
+ void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
// C++ related functions.
@@ -519,9 +504,12 @@ private:
/// a C++ destructor Decl.
void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
- /// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals.
+ /// EmitCXXGlobalInitFunc - Emit the function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
+ /// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals.
+ void EmitCXXGlobalDtorFunc();
+
void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D);
// FIXME: Hardcoding priority here is gross.
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 32555ab70579..f2a73f1c2d12 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -469,8 +469,26 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
mangleName(Qualifier->getAsNamespace());
break;
case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate:
- mangleType(QualType(Qualifier->getAsType(), 0));
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ const Type *QTy = Qualifier->getAsType();
+
+ if (const TemplateSpecializationType *TST =
+ dyn_cast<TemplateSpecializationType>(QTy)) {
+ if (!mangleSubstitution(QualType(TST, 0))) {
+ TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
+ assert(TD && "FIXME: Support dependent template names");
+ mangleTemplatePrefix(TD);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, TST->getArgs(),
+ TST->getNumArgs());
+ addSubstitution(QualType(TST, 0));
+ }
+ } else {
+ // We use the QualType mangle type variant here because it handles
+ // substitutions.
+ mangleType(QualType(QTy, 0));
+ }
+ }
break;
case NestedNameSpecifier::Identifier:
// Member expressions can have these without prefixes.
@@ -1144,29 +1162,8 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
void CXXNameMangler::mangleType(const TypenameType *T) {
// Typename types are always nested
Out << 'N';
-
- const Type *QTy = T->getQualifier()->getAsType();
- if (const TemplateSpecializationType *TST =
- dyn_cast<TemplateSpecializationType>(QTy)) {
- if (!mangleSubstitution(QualType(TST, 0))) {
- TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
- assert(TD && "FIXME: Support dependent template names");
- mangleTemplatePrefix(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, TST->getArgs(),
- TST->getNumArgs());
- addSubstitution(QualType(TST, 0));
- }
- } else if (const TemplateTypeParmType *TTPT =
- dyn_cast<TemplateTypeParmType>(QTy)) {
- // We use the QualType mangle type variant here because it handles
- // substitutions.
- mangleType(QualType(TTPT, 0));
- } else
- assert(false && "Unhandled type!");
-
+ mangleUnresolvedScope(T->getQualifier());
mangleSourceName(T->getIdentifier());
-
Out << 'E';
}
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 97f94b69b432..62656b95da1b 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -21,10 +21,8 @@
#include "CGCXX.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h"
-
-namespace llvm {
- template<typename T> class SmallVectorImpl;
-}
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
namespace clang {
class ASTContext;
@@ -37,6 +35,33 @@ namespace clang {
namespace CodeGen {
class CovariantThunkAdjustment;
class ThunkAdjustment;
+
+/// MangleBuffer - a convenient class for storing a name which is
+/// either the result of a mangling or is a constant string with
+/// external memory ownership.
+class MangleBuffer {
+public:
+ void setString(llvm::StringRef Ref) {
+ String = Ref;
+ }
+
+ llvm::SmallVectorImpl<char> &getBuffer() {
+ return Buffer;
+ }
+
+ llvm::StringRef getString() const {
+ if (!String.empty()) return String;
+ return Buffer.str();
+ }
+
+ operator llvm::StringRef() const {
+ return getString();
+ }
+
+private:
+ llvm::StringRef String;
+ llvm::SmallString<256> Buffer;
+};
/// MangleContext - Context for tracking state which persists across multiple
/// calls to the C++ name mangler.
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
index a09ba095f119..7e61a1d414e0 100644
--- a/lib/Driver/Arg.cpp
+++ b/lib/Driver/Arg.cpp
@@ -10,6 +10,7 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang::driver;
@@ -155,14 +156,12 @@ SeparateArg::SeparateArg(const Option *Opt, unsigned Index, unsigned _NumValues,
void SeparateArg::render(const ArgList &Args, ArgStringList &Output) const {
if (getOption().hasForceJoinedRender()) {
assert(getNumValues() == 1 && "Cannot force joined render with > 1 args.");
- // FIXME: Avoid std::string.
- std::string Joined(getOption().getName());
- Joined += Args.getArgString(getIndex());
- Output.push_back(Args.MakeArgString(Joined.c_str()));
+ Output.push_back(Args.MakeArgString(llvm::StringRef(getOption().getName()) +
+ getValue(Args, 0)));
} else {
Output.push_back(Args.getArgString(getIndex()));
for (unsigned i = 0; i < NumValues; ++i)
- Output.push_back(Args.getArgString(getIndex() + 1 + i));
+ Output.push_back(getValue(Args, i));
}
}
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index b819cda89c09..227f79a75b71 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -61,10 +61,21 @@ void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J,
OS << " \"" << C->getExecutable() << '"';
for (ArgStringList::const_iterator it = C->getArguments().begin(),
ie = C->getArguments().end(); it != ie; ++it) {
- if (Quote)
- OS << " \"" << *it << '"';
- else
- OS << ' ' << *it;
+ OS << ' ';
+ if (!Quote) {
+ OS << *it;
+ continue;
+ }
+
+ // Quote the argument and escape shell special characters; this isn't
+ // really complete but is good enough.
+ OS << '"';
+ for (const char *s = *it; *s; ++s) {
+ if (*s == '"' || *s == '\\' || *s == '$')
+ OS << '\\';
+ OS << *s;
+ }
+ OS << '"';
}
OS << Terminator;
} else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
@@ -123,8 +134,34 @@ int Compilation::ExecuteCommand(const Command &C,
std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
Argv[C.getArguments().size() + 1] = 0;
- if (getDriver().CCCEcho || getArgs().hasArg(options::OPT_v))
- PrintJob(llvm::errs(), C, "\n", false);
+ if (getDriver().CCCEcho || getDriver().CCPrintOptions ||
+ getArgs().hasArg(options::OPT_v)) {
+ llvm::raw_ostream *OS = &llvm::errs();
+
+ // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
+ // output stream.
+ if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
+ std::string Error;
+ OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename,
+ Error,
+ llvm::raw_fd_ostream::F_Append);
+ if (!Error.empty()) {
+ getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
+ << Error;
+ FailingCommand = &C;
+ delete OS;
+ return 1;
+ }
+ }
+
+ if (getDriver().CCPrintOptions)
+ *OS << "[Logging clang options]";
+
+ PrintJob(*OS, C, "\n", /*Quote=*/getDriver().CCPrintOptions);
+
+ if (OS != &llvm::errs())
+ delete OS;
+ }
std::string Error;
int Res =
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 3257ee55a7b9..acfff386f485 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -51,10 +51,10 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
DefaultImageName(_DefaultImageName),
DriverTitle("clang \"gcc-compatible\" driver"),
Host(0),
- CCCGenericGCCName("gcc"), CCCIsCXX(false), CCCEcho(false),
- CCCPrintBindings(false), CheckInputsExist(true), CCCUseClang(true),
- CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true),
- SuppressMissingInputWarning(false) {
+ CCCGenericGCCName("gcc"), CCPrintOptionsFilename(0), CCCIsCXX(false),
+ CCCEcho(false), CCCPrintBindings(false), CCPrintOptions(false),
+ CheckInputsExist(true), CCCUseClang(true), CCCUseClangCXX(true),
+ CCCUseClangCPP(true), CCCUsePCH(true), SuppressMissingInputWarning(false) {
if (IsProduction) {
// In a "production" build, only use clang on architectures we expect to
// work, and don't use clang C++.
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index f69d5d806d28..de1e4592b342 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -167,11 +167,13 @@ Option *OptTable::CreateOption(unsigned id) const {
if (info.Flags & RenderAsInput)
Opt->setNoOptAsInput(true);
if (info.Flags & RenderJoined) {
- assert(info.Kind == Option::SeparateClass && "Invalid option.");
+ assert((info.Kind == Option::JoinedOrSeparateClass ||
+ info.Kind == Option::SeparateClass) && "Invalid option.");
Opt->setForceJoinedRender(true);
}
if (info.Flags & RenderSeparate) {
- assert(info.Kind == Option::JoinedClass && "Invalid option.");
+ assert((info.Kind == Option::JoinedOrSeparateClass ||
+ info.Kind == Option::JoinedClass) && "Invalid option.");
Opt->setForceSeparateRender(true);
}
if (info.Flags & Unsupported)
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 2f8d714504ba..105eab06af5f 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -394,9 +394,9 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
// this. Perhaps put under -pedantic?
if (getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::thumb)
- OSXVersion = 0;
+ OSXTarget = 0;
else
- iPhoneVersion = 0;
+ iPhoneOSTarget = 0;
}
if (OSXTarget) {
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 6dd64dec9ee3..0d5b2a3f4747 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -96,6 +96,8 @@ public:
return TargetIsIPhoneOS;
}
+ bool isTargetInitialized() const { return TargetInitialized; }
+
void getTargetVersion(unsigned (&Res)[3]) const {
assert(TargetInitialized && "Target not initialized!");
Res[0] = TargetVersion[0];
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index bc521008cf7c..1c34df05b1c5 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -655,6 +655,12 @@ static std::string getEffectiveClangTriple(const Driver &D,
} else {
const toolchains::Darwin &DarwinTC(
reinterpret_cast<const toolchains::Darwin&>(TC));
+
+ // If the target isn't initialized (e.g., an unknown Darwin platform, return
+ // the default triple).
+ if (!DarwinTC.isTargetInitialized())
+ return Triple.getTriple();
+
unsigned Version[3];
DarwinTC.getTargetVersion(Version);
@@ -686,6 +692,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ bool KernelOrKext = Args.hasArg(options::OPT_mkernel,
+ options::OPT_fapple_kext);
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
@@ -870,7 +878,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
options::OPT_fno_asynchronous_unwind_tables,
getToolChain().IsUnwindTablesDefault() &&
- !Args.hasArg(options::OPT_mkernel));
+ !KernelOrKext);
if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
AsynchronousUnwindTables))
CmdArgs.push_back("-munwind-tables");
@@ -1029,12 +1037,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ // -fhosted is default.
+ if (KernelOrKext || Args.hasFlag(options::OPT_ffreestanding,
+ options::OPT_fhosted,
+ false))
+ CmdArgs.push_back("-ffreestanding");
+
// Forward -f (flag) options which we can pass directly.
Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior);
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
- Args.AddLastArg(CmdArgs, options::OPT_ffreestanding);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
- Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions);
+
+ // -flax-vector-conversions is default.
+ if (!Args.hasFlag(options::OPT_flax_vector_conversions,
+ options::OPT_fno_lax_vector_conversions))
+ CmdArgs.push_back("-fno-lax-vector-conversions");
+
Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics);
Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only);
@@ -1080,6 +1098,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks");
}
+ // -fno-access-control is default (for now).
+ if (Args.hasFlag(options::OPT_faccess_control,
+ options::OPT_fno_access_control,
+ false))
+ CmdArgs.push_back("-faccess-control");
+
// -fexceptions=0 is default.
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
CmdArgs.push_back("-fexceptions");
@@ -1088,7 +1112,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fsjlj-exceptions");
// -frtti is default.
- if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
+ if (KernelOrKext ||
+ !Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-fno-rtti");
// -fsigned-char is default.
@@ -1101,6 +1126,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_threadsafe_statics))
CmdArgs.push_back("-fno-threadsafe-statics");
+ // -fuse-cxa-atexit is default.
+ if (KernelOrKext || !Args.hasFlag(options::OPT_fuse_cxa_atexit,
+ options::OPT_fno_use_cxa_atexit))
+ CmdArgs.push_back("-fno-use-cxa-atexit");
+
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 3bf1fab1c27d..935c41524370 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -83,7 +83,7 @@ public:
return false;
}
- virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
+ virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
}
@@ -293,8 +293,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
Clang.getTargetOpts()));
if (!Clang.hasTarget()) {
- Clang.takeSourceManager();
- Clang.takeFileManager();
Clang.takeDiagnosticClient();
Clang.takeDiagnostics();
return 0;
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 02d6cec8fcab..d069e8f42f26 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -164,11 +164,12 @@ public:
} // end anonymous namespace
typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap;
-typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
-typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
namespace {
class PTHWriter {
+ typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
+ typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
+
IDMap IM;
llvm::raw_fd_ostream& Out;
Preprocessor& PP;
@@ -272,7 +273,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
// Pad 0's so that we emit tokens to a 4-byte alignment.
// This speed up reading them back in.
Pad(Out, 4);
- Offset off = (Offset) Out.tell();
+ Offset TokenOff = (Offset) Out.tell();
// Keep track of matching '#if' ... '#endif'.
typedef std::vector<std::pair<Offset, unsigned> > PPCondTable;
@@ -418,7 +419,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
Emit32(PPCond.size());
for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) {
- Emit32(PPCond[i].first - off);
+ Emit32(PPCond[i].first - TokenOff);
uint32_t x = PPCond[i].second;
assert(x != 0 && "PPCond entry not backpatched.");
// Emit zero for #endifs. This allows us to do checking when
@@ -426,7 +427,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
Emit32(x == i ? 0 : x);
}
- return PTHEntry(off, PPCondOff);
+ return PTHEntry(TokenOff, PPCondOff);
}
Offset PTHWriter::EmitCachedSpellings() {
@@ -452,7 +453,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) {
// Write the name of the MainFile.
if (!MainFile.empty()) {
- EmitString(MainFile);
+ EmitString(MainFile);
} else {
// String with 0 bytes.
Emit16(0);
@@ -549,7 +550,8 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
// Lex through the entire file. This will populate SourceManager with
// all of the header information.
Token Tok;
- PP.EnterMainSourceFile();
+ if (PP.EnterMainSourceFile())
+ return;
do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
// Generate the PTH file.
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 3bc566192965..7b4932d787a1 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -107,15 +107,13 @@ void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel,
static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
unsigned argc, char **argv,
- llvm::OwningPtr<DiagnosticClient> &DiagClient) {
+ Diagnostic &Diags) {
std::string ErrorInfo;
- llvm::raw_ostream *OS =
- new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo);
+ llvm::OwningPtr<llvm::raw_ostream> OS(
+ new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo));
if (!ErrorInfo.empty()) {
- // FIXME: Do not fail like this.
- llvm::errs() << "error opening -dump-build-information file '"
- << DiagOpts.DumpBuildInformation << "', option ignored!\n";
- delete OS;
+ Diags.Report(diag::err_fe_unable_to_open_logfile)
+ << DiagOpts.DumpBuildInformation << ErrorInfo;
return;
}
@@ -126,8 +124,8 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
// Chain in a diagnostic client which will log the diagnostics.
DiagnosticClient *Logger =
- new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true);
- DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger));
+ new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true);
+ Diags.setClient(new ChainedDiagnosticClient(Diags.getClient(), Logger));
}
void CompilerInstance::createDiagnostics(int Argc, char **Argv) {
@@ -165,13 +163,12 @@ Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
if (Opts.VerifyDiagnostics)
DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take()));
+ Diags->setClient(DiagClient.take());
if (!Opts.DumpBuildInformation.empty())
- SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient);
+ SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
// Configure our handling of diagnostics.
- Diags->setClient(DiagClient.take());
- if (ProcessWarningOptions(*Diags, Opts))
- return 0;
+ ProcessWarningOptions(*Diags, Opts);
return Diags.take();
}
@@ -227,6 +224,9 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
PP->setPTHManager(PTHMgr);
}
+ if (PPOpts.DetailedRecord)
+ PP->createPreprocessingRecord();
+
InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
// Handle generating dependencies, if requested.
@@ -429,12 +429,7 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
SourceManager &SourceMgr,
const FrontendOptions &Opts) {
// Figure out where to get and map in the main file.
- if (Opts.EmptyInputOnly) {
- const char *EmptyStr = "";
- llvm::MemoryBuffer *SB =
- llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>");
- SourceMgr.createMainFileIDForMemBuffer(SB);
- } else if (InputFile != "-") {
+ if (InputFile != "-") {
const FileEntry *File = FileMgr.getFile(InputFile);
if (File) SourceMgr.createMainFileID(File, SourceLocation());
if (SourceMgr.getMainFileID().isInvalid()) {
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 5798f2f71005..6e18f346d561 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -154,6 +154,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-mcode-model");
Res.push_back(Opts.CodeModel);
}
+ if (!Opts.CXAAtExit)
+ Res.push_back("-fno-use-cxa-atexit");
+ if (Opts.CXXCtorDtorAliases)
+ Res.push_back("-mconstructor-aliases");
if (!Opts.DebugPass.empty()) {
Res.push_back("-mdebug-pass");
Res.push_back(Opts.DebugPass);
@@ -180,8 +184,6 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-mrelocation-model");
Res.push_back(Opts.RelocationModel);
}
- if (Opts.CXXCtorDtorAliases)
- Res.push_back("-mconstructor-aliases");
if (!Opts.VerifyModule)
Res.push_back("-disable-llvm-verifier");
}
@@ -288,6 +290,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::FixIt: return "-fixit";
case frontend::GeneratePCH: return "-emit-pch";
case frontend::GeneratePTH: return "-emit-pth";
+ case frontend::InitOnly: return "-init-only";
case frontend::ParseNoop: return "-parse-noop";
case frontend::ParsePrintCallbacks: return "-parse-print-callbacks";
case frontend::ParseSyntaxOnly: return "-fsyntax-only";
@@ -310,8 +313,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-no-code-completion-debug-printer");
if (Opts.DisableFree)
Res.push_back("-disable-free");
- if (Opts.EmptyInputOnly)
- Res.push_back("-empty-input-only");
if (Opts.RelocatablePCH)
Res.push_back("-relocatable-pch");
if (Opts.ShowHelp)
@@ -575,6 +576,8 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
}
if (!Opts.UsePredefines)
Res.push_back("-undef");
+ if (Opts.DetailedRecord)
+ Res.push_back("-detailed-preprocessing-record");
if (!Opts.ImplicitPCHInclude.empty()) {
Res.push_back("-include-pch");
Res.push_back(Opts.ImplicitPCHInclude);
@@ -783,6 +786,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
+ Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
+ Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.CodeModel = getLastArgValue(Args, OPT_mcode_model);
Opts.DebugPass = getLastArgValue(Args, OPT_mdebug_pass);
Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
@@ -793,7 +798,6 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic");
- Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
@@ -876,6 +880,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::GeneratePCH; break;
case OPT_emit_pth:
Opts.ProgramAction = frontend::GeneratePTH; break;
+ case OPT_init_only:
+ Opts.ProgramAction = frontend::InitOnly; break;
case OPT_parse_noop:
Opts.ProgramAction = frontend::ParseNoop; break;
case OPT_parse_print_callbacks:
@@ -913,7 +919,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.DebugCodeCompletionPrinter =
!Args.hasArg(OPT_no_code_completion_debug_printer);
Opts.DisableFree = Args.hasArg(OPT_disable_free);
- Opts.EmptyInputOnly = Args.hasArg(OPT_empty_input_only);
Opts.FixItLocations.clear();
for (arg_iterator it = Args.filtered_begin(OPT_fixit_at),
@@ -1232,7 +1237,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
else
Opts.TokenCache = Opts.ImplicitPTHInclude;
Opts.UsePredefines = !Args.hasArg(OPT_undef);
-
+ Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
// Add macros from the command line.
for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U),
ie = Args.filtered_end(); it != ie; ++it) {
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 1e210b42e6d1..251b8e4cb738 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -23,6 +23,18 @@
using namespace clang;
//===----------------------------------------------------------------------===//
+// Custom Actions
+//===----------------------------------------------------------------------===//
+
+ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new ASTConsumer();
+}
+
+void InitOnlyAction::ExecuteAction() {
+}
+
+//===----------------------------------------------------------------------===//
// AST Consumer Actions
//===----------------------------------------------------------------------===//
@@ -185,7 +197,8 @@ void DumpTokensAction::ExecuteAction() {
Preprocessor &PP = getCompilerInstance().getPreprocessor();
// Start preprocessing the specified input file.
Token Tok;
- PP.EnterMainSourceFile();
+ if (PP.EnterMainSourceFile())
+ return;
do {
PP.Lex(Tok);
PP.DumpToken(Tok, true);
@@ -213,7 +226,8 @@ void ParseOnlyAction::ExecuteAction() {
llvm::OwningPtr<Action> PA(new MinimalAction(PP));
Parser P(PP, *PA);
- PP.EnterMainSourceFile();
+ if (PP.EnterMainSourceFile())
+ return;
P.ParseTranslationUnit();
}
@@ -222,7 +236,8 @@ void PreprocessOnlyAction::ExecuteAction() {
Token Tok;
// Start parsing the specified input file.
- PP.EnterMainSourceFile();
+ if (PP.EnterMainSourceFile())
+ return;
do {
PP.Lex(Tok);
} while (Tok.isNot(tok::eof));
@@ -237,7 +252,8 @@ void PrintParseAction::ExecuteAction() {
llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));
Parser P(PP, *PA);
- PP.EnterMainSourceFile();
+ if (PP.EnterMainSourceFile())
+ return;
P.ParseTranslationUnit();
}
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 49eb2a0e600d..e659ff047d76 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/OnDiskHashTable.h"
@@ -150,7 +151,10 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
std::pair<llvm::StringRef,llvm::StringRef> Split =
llvm::StringRef(PP.getPredefines()).split(PCHInclude.str());
llvm::StringRef Left = Split.first, Right = Split.second;
- assert(Left != PP.getPredefines() && "Missing PCH include entry!");
+ if (Left == PP.getPredefines()) {
+ Error("Missing PCH include entry!");
+ return true;
+ }
// If the predefines is equal to the joined left and right halves, we're done!
if (Left.size() + Right.size() == PCHPredef.size() &&
@@ -300,8 +304,10 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
return false;
}
-void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
- PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
+void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI,
+ unsigned ID) {
+ PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID);
+ ++NumHeaderInfos;
}
void PCHValidator::ReadCounter(unsigned Value) {
@@ -321,8 +327,9 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
IdentifierOffsets(0),
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
- TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
- NumStatHits(0), NumStatMisses(0),
+ TotalNumSelectors(0), MacroDefinitionOffsets(0),
+ NumPreallocatedPreprocessingEntities(0),
+ isysroot(isysroot), NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), NumStatementsRead(0),
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
@@ -338,8 +345,9 @@ PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
IdentifierOffsets(0),
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
- TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
- NumStatHits(0), NumStatMisses(0),
+ TotalNumSelectors(0), MacroDefinitionOffsets(0),
+ NumPreallocatedPreprocessingEntities(0),
+ isysroot(isysroot), NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), NumStatementsRead(0),
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
@@ -601,10 +609,8 @@ public:
typedef OnDiskChainedHashTable<PCHIdentifierLookupTrait>
PCHIdentifierLookupTable;
-bool PCHReader::Error(const char *Msg) {
- unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Fatal, Msg);
- Diag(DiagID);
- return true;
+void PCHReader::Error(const char *Msg) {
+ Diag(diag::err_fe_pch_malformed) << Msg;
}
/// \brief Check the contents of the predefines buffer against the
@@ -850,17 +856,6 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
return Failure;
break;
- case pch::SM_HEADER_FILE_INFO: {
- HeaderFileInfo HFI;
- HFI.isImport = Record[0];
- HFI.DirInfo = Record[1];
- HFI.NumIncludes = Record[2];
- HFI.ControllingMacroID = Record[3];
- if (Listener)
- Listener->ReadHeaderFileInfo(HFI);
- break;
- }
-
case pch::SM_SLOC_FILE_ENTRY:
case pch::SM_SLOC_BUFFER_ENTRY:
case pch::SM_SLOC_INSTANTIATION_ENTRY:
@@ -910,6 +905,11 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
return Failure;
}
+ if (Record.size() < 8) {
+ Error("source location entry is incorrect");
+ return Failure;
+ }
+
FileID FID = SourceMgr.createFileID(File,
SourceLocation::getFromRawEncoding(Record[1]),
(SrcMgr::CharacteristicKind)Record[2],
@@ -918,6 +918,14 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile())
.setHasLineDirectives();
+ // Reconstruct header-search information for this file.
+ HeaderFileInfo HFI;
+ HFI.isImport = Record[4];
+ HFI.DirInfo = Record[5];
+ HFI.NumIncludes = Record[6];
+ HFI.ControllingMacroID = Record[7];
+ if (Listener)
+ Listener->ReadHeaderFileInfo(HFI, File->getUID());
break;
}
@@ -928,8 +936,12 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
Record.clear();
unsigned RecCode
= SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
- assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file");
- (void)RecCode;
+
+ if (RecCode != pch::SM_SLOC_BUFFER_BLOB) {
+ Error("PCH record has invalid code");
+ return Failure;
+ }
+
llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBuffer(BlobStart,
BlobStart + BlobLen - 1,
@@ -1038,12 +1050,14 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
MacroInfo *MI = PP->AllocateMacroInfo(Loc);
MI->setIsUsed(isUsed);
+ unsigned NextIndex = 3;
if (RecType == pch::PP_MACRO_FUNCTION_LIKE) {
// Decode function-like macro info.
bool isC99VarArgs = Record[3];
bool isGNUVarArgs = Record[4];
MacroArgs.clear();
unsigned NumArgs = Record[5];
+ NextIndex = 6 + NumArgs;
for (unsigned i = 0; i != NumArgs; ++i)
MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i]));
@@ -1061,6 +1075,13 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
// Remember that we saw this macro last so that we add the tokens that
// form its body to it.
Macro = MI;
+
+ if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) {
+ // We have a macro definition. Load it now.
+ PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro,
+ getMacroDefinition(Record[NextIndex]));
+ }
+
++NumMacrosRead;
break;
}
@@ -1081,6 +1102,64 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
Macro->AddTokenToBody(Tok);
break;
}
+
+ case pch::PP_MACRO_INSTANTIATION: {
+ // If we already have a macro, that means that we've hit the end
+ // of the definition of the macro we were looking for. We're
+ // done.
+ if (Macro)
+ return;
+
+ if (!PP->getPreprocessingRecord()) {
+ Error("missing preprocessing record in PCH file");
+ return;
+ }
+
+ PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
+ if (PPRec.getPreprocessedEntity(Record[0]))
+ return;
+
+ MacroInstantiation *MI
+ = new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]),
+ SourceRange(
+ SourceLocation::getFromRawEncoding(Record[1]),
+ SourceLocation::getFromRawEncoding(Record[2])),
+ getMacroDefinition(Record[4]));
+ PPRec.SetPreallocatedEntity(Record[0], MI);
+ return;
+ }
+
+ case pch::PP_MACRO_DEFINITION: {
+ // If we already have a macro, that means that we've hit the end
+ // of the definition of the macro we were looking for. We're
+ // done.
+ if (Macro)
+ return;
+
+ if (!PP->getPreprocessingRecord()) {
+ Error("missing preprocessing record in PCH file");
+ return;
+ }
+
+ PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
+ if (PPRec.getPreprocessedEntity(Record[0]))
+ return;
+
+ if (Record[1] >= MacroDefinitionsLoaded.size()) {
+ Error("out-of-bounds macro definition record");
+ return;
+ }
+
+ MacroDefinition *MD
+ = new (PPRec) MacroDefinition(DecodeIdentifierInfo(Record[4]),
+ SourceLocation::getFromRawEncoding(Record[5]),
+ SourceRange(
+ SourceLocation::getFromRawEncoding(Record[2]),
+ SourceLocation::getFromRawEncoding(Record[3])));
+ PPRec.SetPreallocatedEntity(Record[0], MD);
+ MacroDefinitionsLoaded[Record[1]] = MD;
+ return;
+ }
}
}
}
@@ -1130,16 +1209,32 @@ void PCHReader::ReadDefinedMacros() {
case pch::PP_MACRO_OBJECT_LIKE:
case pch::PP_MACRO_FUNCTION_LIKE:
- DecodeIdentifierInfo(Record[0]);
+ DecodeIdentifierInfo(Record[0]);
break;
case pch::PP_TOKEN:
// Ignore tokens.
break;
+
+ case pch::PP_MACRO_INSTANTIATION:
+ case pch::PP_MACRO_DEFINITION:
+ // Read the macro record.
+ ReadMacroRecord(Cursor.GetCurrentBitNo());
+ break;
}
}
}
+MacroDefinition *PCHReader::getMacroDefinition(pch::IdentID ID) {
+ if (ID == 0 || ID >= MacroDefinitionsLoaded.size())
+ return 0;
+
+ if (!MacroDefinitionsLoaded[ID])
+ ReadMacroRecord(MacroDefinitionOffsets[ID]);
+
+ return MacroDefinitionsLoaded[ID];
+}
+
/// \brief If we are loading a relocatable PCH file, and the filename is
/// not an absolute path, add the system root to the beginning of the file
/// name.
@@ -1408,11 +1503,6 @@ PCHReader::ReadPCHBlock() {
MaybeAddSystemRootToFilename(OriginalFileName);
break;
- case pch::COMMENT_RANGES:
- Comments = (SourceRange *)BlobStart;
- NumComments = BlobLen / sizeof(SourceRange);
- break;
-
case pch::VERSION_CONTROL_BRANCH_REVISION: {
const std::string &CurBranch = getClangFullRepositoryVersion();
llvm::StringRef PCHBranch(BlobStart, BlobLen);
@@ -1422,6 +1512,19 @@ PCHReader::ReadPCHBlock() {
}
break;
}
+
+ case pch::MACRO_DEFINITION_OFFSETS:
+ MacroDefinitionOffsets = (const uint32_t *)BlobStart;
+ if (PP) {
+ if (!PP->getPreprocessingRecord())
+ PP->createPreprocessingRecord();
+ PP->getPreprocessingRecord()->SetExternalSource(*this, Record[0]);
+ } else {
+ NumPreallocatedPreprocessingEntities = Record[0];
+ }
+
+ MacroDefinitionsLoaded.resize(Record[1]);
+ break;
}
}
Error("premature end of bitstream in PCH file");
@@ -1553,6 +1656,18 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
return Success;
}
+void PCHReader::setPreprocessor(Preprocessor &pp) {
+ PP = &pp;
+
+ if (NumPreallocatedPreprocessingEntities) {
+ if (!PP->getPreprocessingRecord())
+ PP->createPreprocessingRecord();
+ PP->getPreprocessingRecord()->SetExternalSource(*this,
+ NumPreallocatedPreprocessingEntities);
+ NumPreallocatedPreprocessingEntities = 0;
+ }
+}
+
void PCHReader::InitializeContext(ASTContext &Ctx) {
Context = &Ctx;
assert(Context && "Passed null context!");
@@ -1584,29 +1699,44 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
Context->setObjCFastEnumerationStateType(GetType(FastEnum));
if (unsigned File = SpecialTypes[pch::SPECIAL_TYPE_FILE]) {
QualType FileType = GetType(File);
- assert(!FileType.isNull() && "FILE type is NULL");
+ if (FileType.isNull()) {
+ Error("FILE type is NULL");
+ return;
+ }
if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
Context->setFILEDecl(Typedef->getDecl());
else {
const TagType *Tag = FileType->getAs<TagType>();
- assert(Tag && "Invalid FILE type in PCH file");
+ if (!Tag) {
+ Error("Invalid FILE type in PCH file");
+ return;
+ }
Context->setFILEDecl(Tag->getDecl());
}
}
if (unsigned Jmp_buf = SpecialTypes[pch::SPECIAL_TYPE_jmp_buf]) {
QualType Jmp_bufType = GetType(Jmp_buf);
- assert(!Jmp_bufType.isNull() && "jmp_bug type is NULL");
+ if (Jmp_bufType.isNull()) {
+ Error("jmp_bug type is NULL");
+ return;
+ }
if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
Context->setjmp_bufDecl(Typedef->getDecl());
else {
const TagType *Tag = Jmp_bufType->getAs<TagType>();
- assert(Tag && "Invalid jmp_bug type in PCH file");
+ if (!Tag) {
+ Error("Invalid jmp_bug type in PCH file");
+ return;
+ }
Context->setjmp_bufDecl(Tag->getDecl());
}
}
if (unsigned Sigjmp_buf = SpecialTypes[pch::SPECIAL_TYPE_sigjmp_buf]) {
QualType Sigjmp_bufType = GetType(Sigjmp_buf);
- assert(!Sigjmp_bufType.isNull() && "sigjmp_buf type is NULL");
+ if (Sigjmp_bufType.isNull()) {
+ Error("sigjmp_buf type is NULL");
+ return;
+ }
if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
Context->setsigjmp_bufDecl(Typedef->getDecl());
else {
@@ -1799,10 +1929,8 @@ bool PCHReader::ParseLanguageOptions(
return false;
}
-void PCHReader::ReadComments(std::vector<SourceRange> &Comments) {
- Comments.resize(NumComments);
- std::copy(this->Comments, this->Comments + NumComments,
- Comments.begin());
+void PCHReader::ReadPreprocessedEntities() {
+ ReadDefinedMacros();
}
/// \brief Read and return the type at the given offset.
@@ -1823,45 +1951,65 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
unsigned Code = DeclsCursor.ReadCode();
switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) {
case pch::TYPE_EXT_QUAL: {
- assert(Record.size() == 2 &&
- "Incorrect encoding of extended qualifier type");
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of extended qualifier type");
+ return QualType();
+ }
QualType Base = GetType(Record[0]);
Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]);
return Context->getQualifiedType(Base, Quals);
}
case pch::TYPE_COMPLEX: {
- assert(Record.size() == 1 && "Incorrect encoding of complex type");
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of complex type");
+ return QualType();
+ }
QualType ElemType = GetType(Record[0]);
return Context->getComplexType(ElemType);
}
case pch::TYPE_POINTER: {
- assert(Record.size() == 1 && "Incorrect encoding of pointer type");
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of pointer type");
+ return QualType();
+ }
QualType PointeeType = GetType(Record[0]);
return Context->getPointerType(PointeeType);
}
case pch::TYPE_BLOCK_POINTER: {
- assert(Record.size() == 1 && "Incorrect encoding of block pointer type");
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of block pointer type");
+ return QualType();
+ }
QualType PointeeType = GetType(Record[0]);
return Context->getBlockPointerType(PointeeType);
}
case pch::TYPE_LVALUE_REFERENCE: {
- assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type");
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of lvalue reference type");
+ return QualType();
+ }
QualType PointeeType = GetType(Record[0]);
return Context->getLValueReferenceType(PointeeType);
}
case pch::TYPE_RVALUE_REFERENCE: {
- assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type");
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of rvalue reference type");
+ return QualType();
+ }
QualType PointeeType = GetType(Record[0]);
return Context->getRValueReferenceType(PointeeType);
}
case pch::TYPE_MEMBER_POINTER: {
- assert(Record.size() == 1 && "Incorrect encoding of member pointer type");
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of member pointer type");
+ return QualType();
+ }
QualType PointeeType = GetType(Record[0]);
QualType ClassType = GetType(Record[1]);
return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr());
@@ -1957,7 +2105,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0])));
case pch::TYPE_TYPEDEF:
- assert(Record.size() == 1 && "incorrect encoding of typedef type");
+ if (Record.size() != 1) {
+ Error("incorrect encoding of typedef type");
+ return QualType();
+ }
return Context->getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0])));
case pch::TYPE_TYPEOF_EXPR:
@@ -1976,15 +2127,24 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
return Context->getDecltypeType(ReadTypeExpr());
case pch::TYPE_RECORD:
- assert(Record.size() == 1 && "incorrect encoding of record type");
+ if (Record.size() != 1) {
+ Error("incorrect encoding of record type");
+ return QualType();
+ }
return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0])));
case pch::TYPE_ENUM:
- assert(Record.size() == 1 && "incorrect encoding of enum type");
+ if (Record.size() != 1) {
+ Error("incorrect encoding of enum type");
+ return QualType();
+ }
return Context->getTypeDeclType(cast<EnumDecl>(GetDecl(Record[0])));
case pch::TYPE_ELABORATED: {
- assert(Record.size() == 2 && "incorrect encoding of elaborated type");
+ if (Record.size() != 2) {
+ Error("incorrect encoding of elaborated type");
+ return QualType();
+ }
unsigned Tag = Record[1];
return Context->getElaboratedType(GetType(Record[0]),
(ElaboratedType::TagKind) Tag);
@@ -2329,8 +2489,12 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
llvm::SmallVectorImpl<pch::DeclID> &Decls) {
assert(DC->hasExternalLexicalStorage() &&
"DeclContext has no lexical decls in storage");
+
uint64_t Offset = DeclContextOffsets[DC].first;
- assert(Offset && "DeclContext has no lexical decls in storage");
+ if (Offset == 0) {
+ Error("DeclContext has no lexical decls in storage");
+ return true;
+ }
// Keep track of where we are in the stream, then jump back there
// after reading this context.
@@ -2342,8 +2506,10 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
- (void)RecCode;
- assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block");
+ if (RecCode != pch::DECL_CONTEXT_LEXICAL) {
+ Error("Expected lexical block");
+ return true;
+ }
// Load all of the declaration IDs
Decls.clear();
@@ -2357,7 +2523,10 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
assert(DC->hasExternalVisibleStorage() &&
"DeclContext has no visible decls in storage");
uint64_t Offset = DeclContextOffsets[DC].second;
- assert(Offset && "DeclContext has no visible decls in storage");
+ if (Offset == 0) {
+ Error("DeclContext has no visible decls in storage");
+ return true;
+ }
// Keep track of where we are in the stream, then jump back there
// after reading this context.
@@ -2369,8 +2538,11 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
- (void)RecCode;
- assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block");
+ if (RecCode != pch::DECL_CONTEXT_VISIBLE) {
+ Error("Expected visible block");
+ return true;
+ }
+
if (Record.size() == 0)
return false;
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index c256b4103a7d..4752cd3ea6e2 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h"
@@ -563,9 +564,10 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SOURCE_LOCATION_PRELOADS);
RECORD(STAT_CACHE);
RECORD(EXT_VECTOR_DECLS);
- RECORD(COMMENT_RANGES);
RECORD(VERSION_CONTROL_BRANCH_REVISION);
-
+ RECORD(UNUSED_STATIC_FUNCS);
+ RECORD(MACRO_DEFINITION_OFFSETS);
+
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY);
@@ -573,14 +575,15 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SM_SLOC_BUFFER_BLOB);
RECORD(SM_SLOC_INSTANTIATION_ENTRY);
RECORD(SM_LINE_TABLE);
- RECORD(SM_HEADER_FILE_INFO);
// Preprocessor Block.
BLOCK(PREPROCESSOR_BLOCK);
RECORD(PP_MACRO_OBJECT_LIKE);
RECORD(PP_MACRO_FUNCTION_LIKE);
RECORD(PP_TOKEN);
-
+ RECORD(PP_MACRO_INSTANTIATION);
+ RECORD(PP_MACRO_DEFINITION);
+
// Decls and Types block.
BLOCK(DECLTYPES_BLOCK);
RECORD(TYPE_EXT_QUAL);
@@ -918,6 +921,11 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
+ // HeaderFileInfo fields.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isImport
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // DirInfo
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumIncludes
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // ControllingMacro
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
return Stream.EmitAbbrev(Abbrev);
}
@@ -1019,20 +1027,6 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Stream.EmitRecord(pch::SM_LINE_TABLE, Record);
}
- // Write out entries for all of the header files we know about.
- HeaderSearch &HS = PP.getHeaderSearchInfo();
- Record.clear();
- for (HeaderSearch::header_file_iterator I = HS.header_file_begin(),
- E = HS.header_file_end();
- I != E; ++I) {
- Record.push_back(I->isImport);
- Record.push_back(I->DirInfo);
- Record.push_back(I->NumIncludes);
- AddIdentifierRef(I->ControllingMacro, Record);
- Stream.EmitRecord(pch::SM_HEADER_FILE_INFO, Record);
- Record.clear();
- }
-
// Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets;
@@ -1069,6 +1063,16 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// The source location entry is a file. The blob associated
// with this entry is the file name.
+ // Emit header-search information associated with this file.
+ HeaderFileInfo HFI;
+ HeaderSearch &HS = PP.getHeaderSearchInfo();
+ if (Content->Entry->getUID() < HS.header_file_size())
+ HFI = HS.header_file_begin()[Content->Entry->getUID()];
+ Record.push_back(HFI.isImport);
+ Record.push_back(HFI.DirInfo);
+ Record.push_back(HFI.NumIncludes);
+ AddIdentifierRef(HFI.ControllingMacro, Record);
+
// Turn the file name into an absolute path, if it isn't already.
const char *Filename = Content->Entry->getName();
llvm::sys::Path FilePath(Filename, strlen(Filename));
@@ -1174,6 +1178,7 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
// Loop over all the macro definitions that are live at the end of the file,
// emitting each to the PP section.
+ PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
I != E; ++I) {
// FIXME: This emits macros in hash table order, we should do it in a stable
@@ -1203,6 +1208,12 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
I != E; ++I)
AddIdentifierRef(*I, Record);
}
+
+ // If we have a detailed preprocessing record, record the macro definition
+ // ID that corresponds to this macro.
+ if (PPRec)
+ Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI)));
+
Stream.EmitRecord(Code, Record);
Record.clear();
@@ -1230,25 +1241,68 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
}
++NumMacros;
}
+
+ // If the preprocessor has a preprocessing record, emit it.
+ unsigned NumPreprocessingRecords = 0;
+ if (PPRec) {
+ for (PreprocessingRecord::iterator E = PPRec->begin(), EEnd = PPRec->end();
+ E != EEnd; ++E) {
+ Record.clear();
+
+ if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
+ Record.push_back(NumPreprocessingRecords++);
+ AddSourceLocation(MI->getSourceRange().getBegin(), Record);
+ AddSourceLocation(MI->getSourceRange().getEnd(), Record);
+ AddIdentifierRef(MI->getName(), Record);
+ Record.push_back(getMacroDefinitionID(MI->getDefinition()));
+ Stream.EmitRecord(pch::PP_MACRO_INSTANTIATION, Record);
+ continue;
+ }
+
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
+ // Record this macro definition's location.
+ pch::IdentID ID = getMacroDefinitionID(MD);
+ if (ID != MacroDefinitionOffsets.size()) {
+ if (ID > MacroDefinitionOffsets.size())
+ MacroDefinitionOffsets.resize(ID + 1);
+
+ MacroDefinitionOffsets[ID] = Stream.GetCurrentBitNo();
+ } else
+ MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo());
+
+ Record.push_back(NumPreprocessingRecords++);
+ Record.push_back(ID);
+ AddSourceLocation(MD->getSourceRange().getBegin(), Record);
+ AddSourceLocation(MD->getSourceRange().getEnd(), Record);
+ AddIdentifierRef(MD->getName(), Record);
+ AddSourceLocation(MD->getLocation(), Record);
+ Stream.EmitRecord(pch::PP_MACRO_DEFINITION, Record);
+ continue;
+ }
+ }
+ }
+
Stream.ExitBlock();
-}
-
-void PCHWriter::WriteComments(ASTContext &Context) {
- using namespace llvm;
-
- if (Context.Comments.empty())
- return;
-
- BitCodeAbbrev *CommentAbbrev = new BitCodeAbbrev();
- CommentAbbrev->Add(BitCodeAbbrevOp(pch::COMMENT_RANGES));
- CommentAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
- unsigned CommentCode = Stream.EmitAbbrev(CommentAbbrev);
-
- RecordData Record;
- Record.push_back(pch::COMMENT_RANGES);
- Stream.EmitRecordWithBlob(CommentCode, Record,
- (const char*)&Context.Comments[0],
- Context.Comments.size() * sizeof(SourceRange));
+
+ // Write the offsets table for the preprocessing record.
+ if (NumPreprocessingRecords > 0) {
+ // Write the offsets table for identifier IDs.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::MACRO_DEFINITION_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Record.clear();
+ Record.push_back(pch::MACRO_DEFINITION_OFFSETS);
+ Record.push_back(NumPreprocessingRecords);
+ Record.push_back(MacroDefinitionOffsets.size());
+ Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record,
+ (const char *)&MacroDefinitionOffsets.front(),
+ MacroDefinitionOffsets.size() * sizeof(uint32_t));
+ }
}
//===----------------------------------------------------------------------===//
@@ -2009,13 +2063,12 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Write the remaining PCH contents.
RecordData Record;
- Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
+ Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5);
WriteMetadata(Context, isysroot);
WriteLanguageOptions(Context.getLangOptions());
if (StatCalls && !isysroot)
WriteStatCache(*StatCalls, isysroot);
WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
- WriteComments(Context);
// Write the record of special types.
Record.clear();
@@ -2149,6 +2202,16 @@ pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID;
}
+pch::IdentID PCHWriter::getMacroDefinitionID(MacroDefinition *MD) {
+ if (MD == 0)
+ return 0;
+
+ pch::IdentID &ID = MacroDefinitions[MD];
+ if (ID == 0)
+ ID = MacroDefinitions.size();
+ return ID;
+}
+
void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
if (SelRef.getAsOpaquePtr() == 0) {
Record.push_back(0);
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 44e0e1390604..02afd24c246e 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -448,7 +448,8 @@ static int MacroIDCompare(const void* a, const void* b) {
static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
// -dM mode just scans and ignores all tokens in the files, then dumps out
// the macro table at the end.
- PP.EnterMainSourceFile();
+ if (PP.EnterMainSourceFile())
+ return;
Token Tok;
do PP.Lex(Tok);
@@ -495,7 +496,8 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
PP.addPPCallbacks(Callbacks);
// After we have configured the preprocessor, enter the main file.
- PP.EnterMainSourceFile();
+ if (PP.EnterMainSourceFile())
+ return;
// Consume all of the tokens that come from the predefines buffer. Those
// should not be emitted into the output and are guaranteed to be at the
diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp
index 954e8e23cac7..4ffb2978db7a 100644
--- a/lib/Frontend/RewriteMacros.cpp
+++ b/lib/Frontend/RewriteMacros.cpp
@@ -101,7 +101,8 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
// Get the first preprocessing token.
- PP.EnterMainSourceFile();
+ if (PP.EnterMainSourceFile())
+ return;
Token PPTok;
PP.Lex(PPTok);
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index 4bf507d48dca..ea9635e79849 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -31,7 +31,7 @@
#include <algorithm>
using namespace clang;
-bool clang::ProcessWarningOptions(Diagnostic &Diags,
+void clang::ProcessWarningOptions(Diagnostic &Diags,
const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
@@ -122,6 +122,4 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt);
}
-
- return false;
}
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index fec01549edc5..b09a62731ce1 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -33,7 +33,6 @@
typedef double __m128d __attribute__((__vector_size__(16)));
typedef long long __m128i __attribute__((__vector_size__(16)));
-typedef int __v4si __attribute__((__vector_size__(16)));
typedef short __v8hi __attribute__((__vector_size__(16)));
typedef char __v16qi __attribute__((__vector_size__(16)));
diff --git a/lib/Headers/nmmintrin.h b/lib/Headers/nmmintrin.h
new file mode 100644
index 000000000000..f24352b24691
--- /dev/null
+++ b/lib/Headers/nmmintrin.h
@@ -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 */ \ No newline at end of file
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index 972b2e0d3038..9c8d53d0e489 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -337,6 +337,118 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
/* SSE4 Multiple Packed Sums of Absolute Difference. */
#define _mm_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw128((X), (Y), (M))
+/* These definitions are normally in nmmintrin.h, but gcc puts them in here
+ so we'll do the same. */
+#ifdef __SSE4_2__
+
+/* These specify the type of data that we're comparing. */
+#define _SIDD_UBYTE_OPS 0x00
+#define _SIDD_UWORD_OPS 0x01
+#define _SIDD_SBYTE_OPS 0x02
+#define _SIDD_SWORD_OPS 0x03
+
+/* These specify the type of comparison operation. */
+#define _SIDD_CMP_EQUAL_ANY 0x00
+#define _SIDD_CMP_RANGES 0x04
+#define _SIDD_CMP_EQUAL_EACH 0x08
+#define _SIDD_CMP_EQUAL_ORDERED 0x0c
+
+/* These macros specify the polarity of the operation. */
+#define _SIDD_POSITIVE_POLARITY 0x00
+#define _SIDD_NEGATIVE_POLARITY 0x10
+#define _SIDD_MASKED_POSITIVE_POLARITY 0x20
+#define _SIDD_MASKED_NEGATIVE_POLARITY 0x30
+
+/* These macros are used in _mm_cmpXstri() to specify the return. */
+#define _SIDD_LEAST_SIGNIFICANT 0x00
+#define _SIDD_MOST_SIGNIFICANT 0x40
+
+/* These macros are used in _mm_cmpXstri() to specify the return. */
+#define _SIDD_BIT_MASK 0x00
+#define _SIDD_UNIT_MASK 0x40
+
+/* SSE4.2 Packed Comparison Intrinsics. */
+#define _mm_cmpistrm(A, B, M) __builtin_ia32_pcmpistrm128((A), (B), (M))
+#define _mm_cmpistri(A, B, M) __builtin_ia32_pcmpistri128((A), (B), (M))
+
+#define _mm_cmpestrm(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpestrm128((A), (LA), (B), (LB), (M))
+#define _mm_cmpestri(X, LX, Y, LY, M) \
+ __builtin_ia32_pcmpestri128((A), (LA), (B), (LB), (M))
+
+/* SSE4.2 Packed Comparison Intrinsics and EFlag Reading. */
+#define _mm_cmpistra(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpistria128((A), (LA), (B), (LB), (M))
+#define _mm_cmpistrc(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpistric128((A), (LA), (B), (LB), (M))
+#define _mm_cmpistro(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpistrio128((A), (LA), (B), (LB), (M))
+#define _mm_cmpistrs(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpistris128((A), (LA), (B), (LB), (M))
+#define _mm_cmpistrz(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpistriz128((A), (LA), (B), (LB), (M))
+
+#define _mm_cmpestra(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpestria128((A), (LA), (B), (LB), (M))
+#define _mm_cmpestrc(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpestric128((A), (LA), (B), (LB), (M))
+#define _mm_cmpestro(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpestrio128((A), (LA), (B), (LB), (M))
+#define _mm_cmpestrs(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpestris128((A), (LA), (B), (LB), (M))
+#define _mm_cmpestrz(A, LA, B, LB, M) \
+ __builtin_ia32_pcmpestriz128((A), (LA), (B), (LB), (M))
+
+/* SSE4.2 Compare Packed Data -- Greater Than. */
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_epi64(__m128i __V1, __m128i __V2)
+{
+ return __builtin_ia32_pcmpgtq((__v2di)__V1, (__v2di)__V2);
+}
+
+/* SSE4.2 Accumulate CRC32. */
+static inline unsigned int __attribute__((__always_inline__, __nodebug__))
+_mm_crc32_u8(unsigned int __C, unsigned char __D)
+{
+ return __builtin_ia32_crc32qi(__C, __D);
+}
+
+static inline unsigned int __attribute__((__always_inline__, __nodebug__))
+_mm_crc32_u16(unsigned int __C, unsigned short __D)
+{
+ return __builtin_ia32_crc32hi(__C, __D);
+}
+
+static inline unsigned int __attribute__((__always_inline__, __nodebug__))
+_mm_crc32_u32(unsigned int __C, unsigned int __D)
+{
+ return __builtin_ia32_crc32si(__C, __D);
+}
+
+#ifdef __x86_64__
+static inline unsigned long long __attribute__((__always_inline__, __nodebug__))
+_mm_crc32_u64(unsigned long long __C, unsigned long long __D)
+{
+ return __builtin_ia32_crc32di(__C, __D);
+}
+#endif /* __x86_64__ */
+
+/* SSE4.2 Population Count. */
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_popcnt_u32(unsigned int __A)
+{
+ return __builtin_popcount(__A);
+}
+
+#ifdef __x86_64__
+static inline long long __attribute__((__always_inline__, __nodebug__))
+_mm_popcnt_u64(unsigned long long __A)
+{
+ return __builtin_popcountll(__A);
+}
+#endif /* __x86_64__ */
+
+#endif /* __SSE4_2__ */
#endif /* __SSE4_1__ */
#endif /* _SMMINTRIN_H */
diff --git a/lib/Headers/varargs.h b/lib/Headers/varargs.h
new file mode 100644
index 000000000000..b5477d0a6a48
--- /dev/null
+++ b/lib/Headers/varargs.h
@@ -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
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 2f3888bebc76..06e616bd19c2 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -30,6 +30,7 @@
#include <mmintrin.h>
+typedef int __v4si __attribute__((__vector_size__(16)));
typedef float __v4sf __attribute__((__vector_size__(16)));
typedef float __m128 __attribute__((__vector_size__(16)));
@@ -150,28 +151,24 @@ _mm_max_ps(__m128 a, __m128 b)
static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_and_ps(__m128 a, __m128 b)
{
- typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)((__v4si)a & (__v4si)b);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_andnot_ps(__m128 a, __m128 b)
{
- typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)(~(__v4si)a & (__v4si)b);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_or_ps(__m128 a, __m128 b)
{
- typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)((__v4si)a | (__v4si)b);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_xor_ps(__m128 a, __m128 b)
{
- typedef int __v4si __attribute__((__vector_size__(16)));
return (__m128)((__v4si)a ^ (__v4si)b);
}
diff --git a/lib/Lex/CMakeLists.txt b/lib/Lex/CMakeLists.txt
index 81a1e01f964d..632fbc6340cc 100644
--- a/lib/Lex/CMakeLists.txt
+++ b/lib/Lex/CMakeLists.txt
@@ -16,6 +16,7 @@ add_clang_library(clangLex
PPMacroExpansion.cpp
PTHLexer.cpp
Pragma.cpp
+ PreprocessingRecord.cpp
Preprocessor.cpp
PreprocessorLexer.cpp
ScratchBuffer.cpp
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 6cdb96f37de4..2f89142409a0 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1036,7 +1036,11 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
// If this BCPL-style comment is in a macro definition, transmogrify it into
// a C-style block comment.
- std::string Spelling = PP->getSpelling(Result);
+ bool Invalid = false;
+ std::string Spelling = PP->getSpelling(Result, &Invalid);
+ if (Invalid)
+ return true;
+
assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?");
Spelling[1] = '*'; // Change prefix to "/*".
Spelling += "*/"; // add suffix.
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index 2f1a34c83297..89f6368a277f 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -208,24 +208,31 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
if (Tok.is(tok::string_literal) || // "foo"
Tok.is(tok::wide_string_literal) || // L"foo"
Tok.is(tok::char_constant)) { // 'x' and L'x'.
- std::string Str = Lexer::Stringify(PP.getSpelling(Tok));
- Result.append(Str.begin(), Str.end());
+ bool Invalid = false;
+ std::string TokStr = PP.getSpelling(Tok, &Invalid);
+ if (!Invalid) {
+ std::string Str = Lexer::Stringify(TokStr);
+ Result.append(Str.begin(), Str.end());
+ }
} else {
// Otherwise, just append the token. Do some gymnastics to get the token
// in place and avoid copies where possible.
unsigned CurStrLen = Result.size();
Result.resize(CurStrLen+Tok.getLength());
const char *BufPtr = &Result[CurStrLen];
- unsigned ActualTokLen = PP.getSpelling(Tok, BufPtr);
-
- // If getSpelling returned a pointer to an already uniqued version of the
- // string instead of filling in BufPtr, memcpy it onto our string.
- if (BufPtr != &Result[CurStrLen])
- memcpy(&Result[CurStrLen], BufPtr, ActualTokLen);
-
- // If the token was dirty, the spelling may be shorter than the token.
- if (ActualTokLen != Tok.getLength())
- Result.resize(CurStrLen+ActualTokLen);
+ bool Invalid = false;
+ unsigned ActualTokLen = PP.getSpelling(Tok, BufPtr, &Invalid);
+
+ if (!Invalid) {
+ // If getSpelling returned a pointer to an already uniqued version of
+ // the string instead of filling in BufPtr, memcpy it onto our string.
+ if (BufPtr != &Result[CurStrLen])
+ memcpy(&Result[CurStrLen], BufPtr, ActualTokLen);
+
+ // If the token was dirty, the spelling may be shorter than the token.
+ if (ActualTokLen != Tok.getLength())
+ Result.resize(CurStrLen+ActualTokLen);
+ }
}
}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index cddc6cff727a..7b601010b20d 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -71,7 +71,11 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
if (II == 0) {
- std::string Spelling = getSpelling(MacroNameTok);
+ bool Invalid = false;
+ std::string Spelling = getSpelling(MacroNameTok, &Invalid);
+ if (Invalid)
+ return;
+
const IdentifierInfo &Info = Identifiers.get(Spelling);
if (Info.isCPlusPlusOperatorKeyword())
// C++ 2.5p2: Alternative tokens behave the same as its primary token
@@ -204,7 +208,12 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// to spell an i/e in a strange way that is another letter. Skipping this
// allows us to avoid looking up the identifier info for #define/#undef and
// other common directives.
- const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation());
+ bool Invalid = false;
+ const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation(),
+ &Invalid);
+ if (Invalid)
+ return;
+
char FirstChar = RawCharData[0];
if (FirstChar >= 'a' && FirstChar <= 'z' &&
FirstChar != 'i' && FirstChar != 'e') {
@@ -614,8 +623,11 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
llvm::SmallString<64> IntegerBuffer;
IntegerBuffer.resize(DigitTok.getLength());
const char *DigitTokBegin = &IntegerBuffer[0];
- unsigned ActualLength = PP.getSpelling(DigitTok, DigitTokBegin);
-
+ bool Invalid = false;
+ unsigned ActualLength = PP.getSpelling(DigitTok, DigitTokBegin, &Invalid);
+ if (Invalid)
+ return true;
+
// Verify that we have a simple digit-sequence, and compute the value. This
// is always a simple digit string computed in decimal, so we do this manually
// here.
@@ -900,8 +912,12 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
// Verify that there is nothing after the string, other than EOM.
CheckEndOfDirective("ident");
- if (Callbacks)
- Callbacks->Ident(Tok.getLocation(), getSpelling(StrTok));
+ if (Callbacks) {
+ bool Invalid = false;
+ std::string Str = getSpelling(StrTok, &Invalid);
+ if (!Invalid)
+ Callbacks->Ident(Tok.getLocation(), Str);
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 81e6bf809025..6d1c132fc0a9 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -80,8 +80,10 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
}
// Get the MemoryBuffer for this FID, if it fails, we fail.
- const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID);
- if (!InputFile)
+ bool Invalid = false;
+ const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID,
+ &Invalid);
+ if (Invalid)
return true;
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 5fe2ef172e2f..ffae8ab6afb1 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -542,9 +542,13 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
return false;
case tok::angle_string_literal:
- case tok::string_literal:
- Filename = PP.getSpelling(Tok, FilenameBuffer);
+ case tok::string_literal: {
+ bool Invalid = false;
+ Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid);
+ if (Invalid)
+ return false;
break;
+ }
case tok::less:
// This could be a <foo/bar.h> file coming from a macro expansion. In this
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 654d4606a959..92332a006861 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -287,7 +287,10 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Reserve a buffer to get the spelling.
llvm::SmallString<128> FilenameBuffer;
- llvm::StringRef Filename = getSpelling(FilenameTok, FilenameBuffer);
+ bool Invalid = false;
+ llvm::StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid);
+ if (Invalid)
+ return;
bool isAngled =
GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
new file mode 100644
index 000000000000..6966c38b23d8
--- /dev/null
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -0,0 +1,128 @@
+//===--- PreprocessingRecord.cpp - 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 implements the PreprocessingRecord class, which maintains a record
+// of what occurred during preprocessing, and its helpers.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Token.h"
+
+using namespace clang;
+
+ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { }
+
+void PreprocessingRecord::MaybeLoadPreallocatedEntities() const {
+ if (!ExternalSource || LoadedPreallocatedEntities)
+ return;
+
+ LoadedPreallocatedEntities = true;
+ ExternalSource->ReadPreprocessedEntities();
+}
+
+PreprocessingRecord::PreprocessingRecord()
+ : ExternalSource(0), NumPreallocatedEntities(0),
+ LoadedPreallocatedEntities(false)
+{
+}
+
+PreprocessingRecord::iterator
+PreprocessingRecord::begin(bool OnlyLocalEntities) {
+ if (OnlyLocalEntities)
+ return PreprocessedEntities.begin() + NumPreallocatedEntities;
+
+ MaybeLoadPreallocatedEntities();
+ return PreprocessedEntities.begin();
+}
+
+PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) {
+ if (!OnlyLocalEntities)
+ MaybeLoadPreallocatedEntities();
+
+ return PreprocessedEntities.end();
+}
+
+PreprocessingRecord::const_iterator
+PreprocessingRecord::begin(bool OnlyLocalEntities) const {
+ if (OnlyLocalEntities)
+ return PreprocessedEntities.begin() + NumPreallocatedEntities;
+
+ MaybeLoadPreallocatedEntities();
+ return PreprocessedEntities.begin();
+}
+
+PreprocessingRecord::const_iterator
+PreprocessingRecord::end(bool OnlyLocalEntities) const {
+ if (!OnlyLocalEntities)
+ MaybeLoadPreallocatedEntities();
+
+ return PreprocessedEntities.end();
+}
+
+void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
+ PreprocessedEntities.push_back(Entity);
+}
+
+void PreprocessingRecord::SetExternalSource(
+ ExternalPreprocessingRecordSource &Source,
+ unsigned NumPreallocatedEntities) {
+ assert(!ExternalSource &&
+ "Preprocessing record already has an external source");
+ ExternalSource = &Source;
+ this->NumPreallocatedEntities = NumPreallocatedEntities;
+ PreprocessedEntities.insert(PreprocessedEntities.begin(),
+ NumPreallocatedEntities, 0);
+}
+
+void PreprocessingRecord::SetPreallocatedEntity(unsigned Index,
+ PreprocessedEntity *Entity) {
+ assert(Index < NumPreallocatedEntities &&"Out-of-bounds preallocated entity");
+ PreprocessedEntities[Index] = Entity;
+}
+
+void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
+ MacroDefinition *MD) {
+ MacroDefinitions[Macro] = MD;
+}
+
+MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
+ llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
+ = MacroDefinitions.find(MI);
+ if (Pos == MacroDefinitions.end())
+ return 0;
+
+ return Pos->second;
+}
+
+void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) {
+ if (MacroDefinition *Def = findMacroDefinition(MI))
+ PreprocessedEntities.push_back(
+ new (*this) MacroInstantiation(Id.getIdentifierInfo(),
+ Id.getLocation(),
+ Def));
+}
+
+void PreprocessingRecord::MacroDefined(const IdentifierInfo *II,
+ const MacroInfo *MI) {
+ SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
+ MacroDefinition *Def
+ = new (*this) MacroDefinition(II, MI->getDefinitionLoc(), R);
+ MacroDefinitions[MI] = Def;
+ PreprocessedEntities.push_back(Def);
+}
+
+void PreprocessingRecord::MacroUndefined(const IdentifierInfo *II,
+ const MacroInfo *MI) {
+ llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
+ = MacroDefinitions.find(MI);
+ if (Pos != MacroDefinitions.end())
+ MacroDefinitions.erase(Pos);
+}
+
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 5584b18da15f..9d59300d213e 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -31,6 +31,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Pragma.h"
+#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/ScratchBuffer.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -53,7 +54,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0),
Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0),
- CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0) {
+ CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0) {
ScratchBuf = new ScratchBuffer(SourceMgr);
CounterValue = 0; // __COUNTER__ starts at 0.
OwnsHeaderSearch = OwnsHeaders;
@@ -232,8 +233,9 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
return false;
// Load the actual file's contents.
- const MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
- if (!Buffer)
+ bool Invalid = false;
+ const MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File, &Invalid);
+ if (Invalid)
return true;
// Find the byte position of the truncation point.
@@ -427,10 +429,11 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart,
// Figure out how many physical characters away the specified instantiation
// character is. This needs to take into consideration newlines and
// trigraphs.
- const char *TokPtr = SourceMgr.getCharacterData(TokStart);
+ bool Invalid = false;
+ const char *TokPtr = SourceMgr.getCharacterData(TokStart, &Invalid);
// If they request the first char of the token, we're trivially done.
- if (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr))
+ if (Invalid || (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr)))
return TokStart;
unsigned PhysOffset = 0;
@@ -486,7 +489,7 @@ SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc,
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
-void Preprocessor::EnterMainSourceFile() {
+bool Preprocessor::EnterMainSourceFile() {
// We do not allow the preprocessor to reenter the main file. Doing so will
// cause FileID's to accumulate information from both runs (e.g. #line
// information) and predefined macros aren't guaranteed to be set properly.
@@ -495,8 +498,8 @@ void Preprocessor::EnterMainSourceFile() {
// Enter the main file source buffer.
std::string ErrorStr;
- bool Res = EnterSourceFile(MainFileID, 0, ErrorStr);
- assert(!Res && "Entering main file should not fail!");
+ if (EnterSourceFile(MainFileID, 0, ErrorStr))
+ return true;
// Tell the header info that the main file was entered. If the file is later
// #imported, it won't be re-entered.
@@ -513,8 +516,7 @@ void Preprocessor::EnterMainSourceFile() {
assert(!FID.isInvalid() && "Could not create FileID for predefines?");
// Start parsing the predefines.
- Res = EnterSourceFile(FID, 0, ErrorStr);
- assert(!Res && "Entering predefines should not fail!");
+ return EnterSourceFile(FID, 0, ErrorStr);
}
@@ -626,3 +628,11 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) {
}
CommentHandler::~CommentHandler() { }
+
+void Preprocessor::createPreprocessingRecord() {
+ if (Record)
+ return;
+
+ Record = new PreprocessingRecord;
+ addPPCallbacks(Record);
+}
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index dbd1b8400de3..56bb073e5919 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -396,12 +396,17 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// Get the spelling of the LHS token in Buffer.
const char *BufPtr = &Buffer[0];
- unsigned LHSLen = PP.getSpelling(Tok, BufPtr);
+ bool Invalid = false;
+ unsigned LHSLen = PP.getSpelling(Tok, BufPtr, &Invalid);
if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer!
memcpy(&Buffer[0], BufPtr, LHSLen);
-
+ if (Invalid)
+ return true;
+
BufPtr = &Buffer[LHSLen];
- unsigned RHSLen = PP.getSpelling(RHS, BufPtr);
+ unsigned RHSLen = PP.getSpelling(RHS, BufPtr, &Invalid);
+ if (Invalid)
+ return true;
if (BufPtr != &Buffer[LHSLen]) // Really, we want the chars in Buffer!
memcpy(&Buffer[LHSLen], BufPtr, RHSLen);
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index b96dff573dfa..a66dd96b2599 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -54,7 +54,6 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
if (AttrName.startswith("__") && AttrName.endswith("__"))
AttrName = AttrName.substr(2, AttrName.size() - 4);
- // FIXME: Hand generating this is neither smart nor efficient.
return llvm::StringSwitch<AttributeList::Kind>(AttrName)
.Case("weak", AT_weak)
.Case("weakref", AT_weakref)
@@ -93,6 +92,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("dllimport", AT_dllimport)
.Case("dllexport", AT_dllexport)
.Case("may_alias", IgnoredAttribute) // FIXME: TBAA
+ .Case("gcc_tdiag", IgnoredAttribute) // GCC diagnostics type checking.
.Case("base_check", AT_base_check)
.Case("deprecated", AT_deprecated)
.Case("visibility", AT_visibility)
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 12c5b6c70483..cff35b72c45a 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -110,7 +110,7 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- // check if we have a "paramterized" attribute
+ // check if we have a "parameterized" attribute
if (Tok.is(tok::l_paren)) {
ConsumeParen(); // ignore the left paren loc for now
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index b92e7539deda..9e232cbf325d 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -167,7 +167,10 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
assert(Tok.is(tok::string_literal) && "Not a string literal!");
llvm::SmallString<8> LangBuffer;
// LangBuffer is guaranteed to be big enough.
- llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer);
+ bool Invalid = false;
+ llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid);
+ if (Invalid)
+ return DeclPtrTy();
SourceLocation Loc = ConsumeStringToken();
@@ -1517,6 +1520,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (!Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_expected_lbrace_after_base_specifiers);
+
+ if (TagDecl)
+ Actions.ActOnTagDefinitionError(CurScope, TagDecl);
return;
}
}
@@ -1593,11 +1599,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
ParseLexedMethodDefs(getCurrentClass());
}
+ Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc);
+
// Leave the class scope.
ParsingDef.Pop();
ClassScope.Exit();
-
- Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc);
}
/// ParseConstructorInitializer - Parse a C++ constructor initializer,
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index e7a771edda44..d45aaed70e54 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -21,20 +21,6 @@
#include "ParsePragma.h"
using namespace clang;
-/// \brief A comment handler that passes comments found by the preprocessor
-/// to the parser action.
-class ActionCommentHandler : public CommentHandler {
- Action &Actions;
-
-public:
- explicit ActionCommentHandler(Action &Actions) : Actions(Actions) { }
-
- virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) {
- Actions.ActOnComment(Comment);
- return false;
- }
-};
-
Parser::Parser(Preprocessor &pp, Action &actions)
: CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
GreaterThanIsOperator(true), ColonIsSacred(false),
@@ -59,9 +45,6 @@ Parser::Parser(Preprocessor &pp, Action &actions)
WeakHandler.reset(new
PragmaWeakHandler(&PP.getIdentifierTable().get("weak"), actions));
PP.AddPragmaHandler(0, WeakHandler.get());
-
- CommentHandler.reset(new ActionCommentHandler(actions));
- PP.AddCommentHandler(CommentHandler.get());
}
/// If a crash happens while the parser is active, print out a line indicating
@@ -317,7 +300,6 @@ Parser::~Parser() {
UnusedHandler.reset();
PP.RemovePragmaHandler(0, WeakHandler.get());
WeakHandler.reset();
- PP.RemoveCommentHandler(CommentHandler.get());
}
/// Initialize - Warm up the parser.
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
new file mode 100644
index 000000000000..c4ceec0f8111
--- /dev/null
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -0,0 +1,369 @@
+//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- 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 analysis_warnings::[Policy,Executor].
+// Together they are used by Sema to issue warnings based on inexpensive
+// static analysis algorithms in libAnalysis.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "AnalysisBasedWarnings.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/Analyses/ReachableCode.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/Support/Casting.h"
+#include <queue>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Unreachable code analysis.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class UnreachableCodeHandler : public reachable_code::Callback {
+ Sema &S;
+ public:
+ UnreachableCodeHandler(Sema &s) : S(s) {}
+
+ void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) {
+ S.Diag(L, diag::warn_unreachable) << R1 << R2;
+ }
+ };
+}
+
+/// CheckUnreachable - Check for unreachable code.
+static void CheckUnreachable(Sema &S, AnalysisContext &AC) {
+ UnreachableCodeHandler UC(S);
+ reachable_code::FindUnreachableCode(AC, UC);
+}
+
+//===----------------------------------------------------------------------===//
+// Check for missing return value.
+//===----------------------------------------------------------------------===//
+
+enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
+ AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
+
+/// CheckFallThrough - Check that we don't fall off the end of a
+/// Statement that should return a value.
+///
+/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
+/// MaybeFallThrough iff we might or might not fall off the end,
+/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
+/// return. We assume NeverFallThrough iff we never fall off the end of the
+/// statement but we may return. We assume that functions not marked noreturn
+/// will return.
+static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
+ CFG *cfg = AC.getCFG();
+ if (cfg == 0)
+ // FIXME: This should be NeverFallThrough
+ return NeverFallThroughOrReturn;
+
+ // The CFG leaves in dead things, and we don't want the dead code paths to
+ // confuse us, so we mark all live things first.
+ std::queue<CFGBlock*> workq;
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(),
+ live);
+
+ bool AddEHEdges = AC.getAddEHEdges();
+ if (!AddEHEdges && count != cfg->getNumBlockIDs())
+ // When there are things remaining dead, and we didn't add EH edges
+ // from CallExprs to the catch clauses, we have to go back and
+ // mark them as live.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()]) {
+ if (b.pred_begin() == b.pred_end()) {
+ if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator()))
+ // When not adding EH edges from calls, catch clauses
+ // can otherwise seem dead. Avoid noting them as dead.
+ count += reachable_code::ScanReachableFromBlock(b, live);
+ continue;
+ }
+ }
+ }
+
+ // Now we know what is live, we check the live precessors of the exit block
+ // and look for fall through paths, being careful to ignore normal returns,
+ // and exceptional paths.
+ bool HasLiveReturn = false;
+ bool HasFakeEdge = false;
+ bool HasPlainEdge = false;
+ bool HasAbnormalEdge = false;
+ for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(),
+ E = cfg->getExit().pred_end();
+ I != E;
+ ++I) {
+ CFGBlock& B = **I;
+ if (!live[B.getBlockID()])
+ continue;
+ if (B.size() == 0) {
+ if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+
+ // A labeled empty statement, or the entry block...
+ HasPlainEdge = true;
+ continue;
+ }
+ Stmt *S = B[B.size()-1];
+ if (isa<ReturnStmt>(S)) {
+ HasLiveReturn = true;
+ continue;
+ }
+ if (isa<ObjCAtThrowStmt>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ if (isa<CXXThrowExpr>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
+ if (AS->isMSAsm()) {
+ HasFakeEdge = true;
+ HasLiveReturn = true;
+ continue;
+ }
+ }
+ if (isa<CXXTryStmt>(S)) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+
+ bool NoReturnEdge = false;
+ if (CallExpr *C = dyn_cast<CallExpr>(S)) {
+ if (B.succ_begin()[0] != &cfg->getExit()) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+ Expr *CEE = C->getCallee()->IgnoreParenCasts();
+ if (CEE->getType().getNoReturnAttr()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VD->hasAttr<NoReturnAttr>()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ }
+ }
+ }
+ // FIXME: Add noreturn message sends.
+ if (NoReturnEdge == false)
+ HasPlainEdge = true;
+ }
+ if (!HasPlainEdge) {
+ if (HasLiveReturn)
+ return NeverFallThrough;
+ return NeverFallThroughOrReturn;
+ }
+ if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
+ return MaybeFallThrough;
+ // This says AlwaysFallThrough for calls to functions that are not marked
+ // noreturn, that don't return. If people would like this warning to be more
+ // accurate, such functions should be marked as noreturn.
+ return AlwaysFallThrough;
+}
+
+struct CheckFallThroughDiagnostics {
+ unsigned diag_MaybeFallThrough_HasNoReturn;
+ unsigned diag_MaybeFallThrough_ReturnsNonVoid;
+ unsigned diag_AlwaysFallThrough_HasNoReturn;
+ unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
+ unsigned diag_NeverFallThroughOrReturn;
+ bool funMode;
+
+ static CheckFallThroughDiagnostics MakeForFunction() {
+ CheckFallThroughDiagnostics D;
+ D.diag_MaybeFallThrough_HasNoReturn =
+ diag::warn_falloff_noreturn_function;
+ D.diag_MaybeFallThrough_ReturnsNonVoid =
+ diag::warn_maybe_falloff_nonvoid_function;
+ D.diag_AlwaysFallThrough_HasNoReturn =
+ diag::warn_falloff_noreturn_function;
+ D.diag_AlwaysFallThrough_ReturnsNonVoid =
+ diag::warn_falloff_nonvoid_function;
+ D.diag_NeverFallThroughOrReturn =
+ diag::warn_suggest_noreturn_function;
+ D.funMode = true;
+ return D;
+ }
+
+ static CheckFallThroughDiagnostics MakeForBlock() {
+ CheckFallThroughDiagnostics D;
+ D.diag_MaybeFallThrough_HasNoReturn =
+ diag::err_noreturn_block_has_return_expr;
+ D.diag_MaybeFallThrough_ReturnsNonVoid =
+ diag::err_maybe_falloff_nonvoid_block;
+ D.diag_AlwaysFallThrough_HasNoReturn =
+ diag::err_noreturn_block_has_return_expr;
+ D.diag_AlwaysFallThrough_ReturnsNonVoid =
+ diag::err_falloff_nonvoid_block;
+ D.diag_NeverFallThroughOrReturn =
+ diag::warn_suggest_noreturn_block;
+ D.funMode = false;
+ return D;
+ }
+
+ bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid,
+ bool HasNoReturn) const {
+ if (funMode) {
+ return (D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
+ == Diagnostic::Ignored || ReturnsVoid)
+ && (D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
+ == Diagnostic::Ignored || !HasNoReturn)
+ && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid);
+ }
+
+ // For blocks.
+ return ReturnsVoid && !HasNoReturn
+ && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid);
+ }
+};
+
+/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
+/// function that should return a value. Check that we don't fall off the end
+/// of a noreturn function. We assume that functions and blocks not marked
+/// noreturn will return.
+static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
+ QualType BlockTy,
+ const CheckFallThroughDiagnostics& CD,
+ AnalysisContext &AC) {
+
+ bool ReturnsVoid = false;
+ bool HasNoReturn = false;
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ ReturnsVoid = FD->getResultType()->isVoidType();
+ HasNoReturn = FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
+ }
+ else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ ReturnsVoid = MD->getResultType()->isVoidType();
+ HasNoReturn = MD->hasAttr<NoReturnAttr>();
+ }
+ else if (isa<BlockDecl>(D)) {
+ if (const FunctionType *FT =
+ BlockTy->getPointeeType()->getAs<FunctionType>()) {
+ if (FT->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (FT->getNoReturnAttr())
+ HasNoReturn = true;
+ }
+ }
+
+ Diagnostic &Diags = S.getDiagnostics();
+
+ // Short circuit for compilation speed.
+ if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
+ return;
+
+ // FIXME: Function try block
+ if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+ switch (CheckFallThrough(AC)) {
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ S.Diag(Compound->getRBracLoc(),
+ CD.diag_MaybeFallThrough_HasNoReturn);
+ else if (!ReturnsVoid)
+ S.Diag(Compound->getRBracLoc(),
+ CD.diag_MaybeFallThrough_ReturnsNonVoid);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ S.Diag(Compound->getRBracLoc(),
+ CD.diag_AlwaysFallThrough_HasNoReturn);
+ else if (!ReturnsVoid)
+ S.Diag(Compound->getRBracLoc(),
+ CD.diag_AlwaysFallThrough_ReturnsNonVoid);
+ break;
+ case NeverFallThroughOrReturn:
+ if (ReturnsVoid && !HasNoReturn)
+ S.Diag(Compound->getLBracLoc(),
+ CD.diag_NeverFallThroughOrReturn);
+ break;
+ case NeverFallThrough:
+ break;
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
+// warnings on a function, method, or block.
+//===----------------------------------------------------------------------===//
+
+clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
+ Diagnostic &D = S.getDiagnostics();
+
+ enableCheckFallThrough = 1;
+
+ enableCheckUnreachable = (unsigned)
+ (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored);
+}
+
+void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D,
+ QualType BlockTy) {
+
+ assert(BlockTy.isNull() || isa<BlockDecl>(D));
+
+ // Do not do any analysis for declarations in system headers if we are
+ // going to just ignore them.
+ if (S.getDiagnostics().getSuppressSystemWarnings() &&
+ S.SourceMgr.isInSystemHeader(D->getLocation()))
+ return;
+
+ // We avoid doing analysis-based warnings when there are errors for
+ // two reasons:
+ // (1) The CFGs often can't be constructed (if the body is invalid), so
+ // don't bother trying.
+ // (2) The code already has problems; running the analysis just takes more
+ // time.
+ if (S.getDiagnostics().hasErrorOccurred())
+ return;
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // For function templates, class templates and member function templates
+ // we'll do the analysis at instantiation time.
+ if (FD->isDependentContext())
+ return;
+ }
+
+ const Stmt *Body = D->getBody();
+ assert(Body);
+
+ // Don't generate EH edges for CallExprs as we'd like to avoid the n^2
+ // explosion for destrutors that can result and the compile time hit.
+ AnalysisContext AC(D, false);
+
+ // Warning: check missing 'return'
+ if (enableCheckFallThrough) {
+ const CheckFallThroughDiagnostics &CD =
+ (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
+ : CheckFallThroughDiagnostics::MakeForFunction());
+ CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC);
+ }
+
+ // Warning: check for unreachable code
+ if (enableCheckUnreachable)
+ CheckUnreachable(S, AC);
+}
diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h
new file mode 100644
index 000000000000..39da1b14d4a9
--- /dev/null
+++ b/lib/Sema/AnalysisBasedWarnings.h
@@ -0,0 +1,35 @@
+//=- AnalysisBasedWarnings.h - Sema warnings based on libAnalysis -*- 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 AnalysisBasedWarnings, a worker object used by Sema
+// that issues warnings based on dataflow-analysis.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
+#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
+
+namespace clang { namespace sema {
+
+class AnalysisBasedWarnings {
+ Sema &S;
+ // The warnings to run.
+ unsigned enableCheckFallThrough : 1;
+ unsigned enableCheckUnreachable : 1;
+
+public:
+
+ AnalysisBasedWarnings(Sema &s);
+ void IssueWarnings(const Decl *D, QualType BlockTy = QualType());
+
+ void disableCheckFallThrough() { enableCheckFallThrough = 0; }
+};
+
+}} // end namespace clang::sema
+
+#endif
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 237803a1c453..ac0dfd6c3af5 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_NO_RTTI 1)
add_clang_library(clangSema
+ AnalysisBasedWarnings.cpp
CodeCompleteConsumer.cpp
IdentifierResolver.cpp
JumpDiagnostics.cpp
diff --git a/lib/Sema/CXXFieldCollector.h b/lib/Sema/CXXFieldCollector.h
index 69d13515fa65..63c6ee3f74ba 100644
--- a/lib/Sema/CXXFieldCollector.h
+++ b/lib/Sema/CXXFieldCollector.h
@@ -58,7 +58,10 @@ public:
}
/// getCurNumField - The number of fields added to the currently parsed class.
- size_t getCurNumFields() const { return FieldCount.back(); }
+ size_t getCurNumFields() const {
+ assert(!FieldCount.empty() && "no currently-parsed class");
+ return FieldCount.back();
+ }
/// getCurFields - Pointer to array of fields added to the currently parsed
/// class.
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index 898b3c230e87..7cd39895f6fd 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -44,7 +44,8 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer);
Parser P(PP, S);
- PP.EnterMainSourceFile();
+ if (PP.EnterMainSourceFile())
+ return;
// Initialize the parser.
P.Initialize();
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 3b4afef70b53..7112687605b7 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -399,8 +399,3 @@ BlockScopeInfo *Sema::getCurBlock() {
return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
}
-
-void Sema::ActOnComment(SourceRange Comment) {
- Context.Comments.push_back(Comment);
-}
-
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 4c258448daf2..b529e5b640ba 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -42,7 +42,6 @@ namespace llvm {
}
namespace clang {
- class AnalysisContext;
class ASTContext;
class ASTConsumer;
class CodeCompleteConsumer;
@@ -321,6 +320,14 @@ public:
Diag(0) {
}
+ AccessedEntity(MemberNonce _,
+ CXXRecordDecl *NamingClass,
+ DeclAccessPair FoundDecl)
+ : Access(FoundDecl.getAccess()), IsMember(true),
+ Target(FoundDecl.getDecl()), NamingClass(NamingClass),
+ Diag(0) {
+ }
+
AccessedEntity(BaseNonce _,
CXXRecordDecl *BaseClass,
CXXRecordDecl *DerivedClass,
@@ -678,8 +685,6 @@ public:
/// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls
llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
- virtual void ActOnComment(SourceRange Comment);
-
//===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp.
//
@@ -778,6 +783,7 @@ public:
const LookupResult &Previous,
Scope *S);
void DiagnoseFunctionSpecifiers(Declarator& D);
+ void DiagnoseShadow(Scope *S, Declarator &D, const LookupResult& R);
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, bool &Redeclaration);
@@ -938,6 +944,10 @@ public:
virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
SourceLocation RBraceLoc);
+ /// ActOnTagDefinitionError - Invoked when there was an unrecoverable
+ /// error parsing the definition of a tag.
+ virtual void ActOnTagDefinitionError(Scope *S, DeclPtrTy TagDecl);
+
EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum,
EnumConstantDecl *LastEnumConst,
SourceLocation IdLoc,
@@ -1126,12 +1136,12 @@ public:
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
void AddOverloadCandidate(NamedDecl *Function,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet);
void AddOverloadCandidate(FunctionDecl *Function,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
@@ -1141,20 +1151,21 @@ public:
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
- void AddMethodCandidate(NamedDecl *Decl, AccessSpecifier Access,
+ void AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversion = false,
bool ForceRValue = false);
- void AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access,
+ void AddMethodCandidate(CXXMethodDecl *Method,
+ DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
@@ -1163,24 +1174,24 @@ public:
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
QualType ObjectTy, Expr **Args, unsigned NumArgs,
@@ -1284,9 +1295,6 @@ public:
OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc);
- /// CheckUnreachable - Check for unreachable code.
- void CheckUnreachable(AnalysisContext &);
-
/// CheckCallReturnType - Checks that a call expression's return type is
/// complete. Returns true on failure. The location passed in is the location
/// that best represents the call.
@@ -1294,15 +1302,9 @@ public:
CallExpr *CE, FunctionDecl *FD);
/// Helpers for dealing with blocks and functions.
- void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, AnalysisContext &);
- void CheckFallThroughForBlock(QualType BlockTy, Stmt *, AnalysisContext &);
bool CheckParmsForFunctionDef(FunctionDecl *FD);
void CheckCXXDefaultArguments(FunctionDecl *FD);
void CheckExtraCXXDefaultArguments(Declarator &D);
- enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
- AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
- ControlFlowKind CheckFallThrough(AnalysisContext &);
-
Scope *getNonFieldDeclScope(Scope *S);
/// \name Name lookup
@@ -2473,10 +2475,11 @@ public:
bool IsImplicitConstructor,
bool AnyErrors);
- /// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl,
- /// mark all its non-trivial member and base destructor declarations
- /// as referenced.
- void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor);
+ /// MarkBaseAndMemberDestructorsReferenced - Given a record decl,
+ /// mark all the non-trivial destructors of its members and bases as
+ /// referenced.
+ void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc,
+ CXXRecordDecl *Record);
/// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual
/// members need to be marked as referenced at the end of the translation
@@ -2617,11 +2620,13 @@ public:
AccessSpecifier LexicalAS);
AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
- NamedDecl *D,
- AccessSpecifier Access);
+ DeclAccessPair FoundDecl);
AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
- NamedDecl *D,
- AccessSpecifier Access);
+ DeclAccessPair FoundDecl);
+ AccessResult CheckAllocationAccess(SourceLocation OperatorLoc,
+ SourceRange PlacementRange,
+ CXXRecordDecl *NamingClass,
+ DeclAccessPair FoundDecl);
AccessResult CheckConstructorAccess(SourceLocation Loc,
CXXConstructorDecl *D,
AccessSpecifier Access);
@@ -2634,8 +2639,7 @@ public:
AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
Expr *ObjectExpr,
Expr *ArgExpr,
- NamedDecl *D,
- AccessSpecifier Access);
+ DeclAccessPair FoundDecl);
AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
QualType Base, QualType Derived,
const CXXBasePath &Path,
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index f0a38d5970cc..40b320c1be5e 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -52,7 +52,7 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
namespace {
struct EffectiveContext {
- EffectiveContext() : Record(0), Function(0) {}
+ EffectiveContext() : Function(0) {}
explicit EffectiveContext(DeclContext *DC) {
if (isa<FunctionDecl>(DC)) {
@@ -60,18 +60,28 @@ struct EffectiveContext {
DC = Function->getDeclContext();
} else
Function = 0;
-
- if (isa<CXXRecordDecl>(DC))
- Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
- else
- Record = 0;
+
+ // C++ [class.access.nest]p1:
+ // A nested class is a member and as such has the same access
+ // rights as any other member.
+ // C++ [class.access]p2:
+ // A member of a class can also access all the names to which
+ // the class has access.
+ // This implies that the privileges of nesting are transitive.
+ while (isa<CXXRecordDecl>(DC)) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ Records.push_back(Record);
+ DC = Record->getDeclContext();
+ }
}
- bool isClass(const CXXRecordDecl *R) const {
- return R->getCanonicalDecl() == Record;
+ bool includesClass(const CXXRecordDecl *R) const {
+ R = R->getCanonicalDecl();
+ return std::find(Records.begin(), Records.end(), R)
+ != Records.end();
}
- CXXRecordDecl *Record;
+ llvm::SmallVector<CXXRecordDecl*, 4> Records;
FunctionDecl *Function;
};
}
@@ -83,48 +93,133 @@ static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
return DeclaringClass;
}
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Friend) {
+ // FIXME: close matches becuse of dependency
+ if (EC.includesClass(Friend))
+ return Sema::AR_accessible;
+
+ return Sema::AR_inaccessible;
+}
+
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FriendDecl *Friend) {
+ if (Type *T = Friend->getFriendType()) {
+ CanQualType CT = T->getCanonicalTypeUnqualified();
+ if (const RecordType *RT = CT->getAs<RecordType>())
+ return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
+
+ // TODO: we can fail early for a lot of type classes.
+ if (T->isDependentType())
+ return Sema::AR_dependent;
+
+ return Sema::AR_inaccessible;
+ }
+
+ NamedDecl *D
+ = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
+
+ // FIXME: declarations with dependent or templated scope.
+
+ // For class templates, we want to check whether any of the records
+ // are possible specializations of the template.
+ if (isa<ClassTemplateDecl>(D)) {
+ for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
+ I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
+ CXXRecordDecl *Record = *I;
+ ClassTemplateDecl *CTD;
+
+ // A specialization of the template...
+ if (isa<ClassTemplateSpecializationDecl>(Record)) {
+ CTD = cast<ClassTemplateSpecializationDecl>(Record)
+ ->getSpecializedTemplate();
+
+ // ... or the template pattern itself.
+ } else {
+ CTD = Record->getDescribedClassTemplate();
+ }
+
+ if (CTD && D == CTD->getCanonicalDecl())
+ return Sema::AR_accessible;
+ }
+
+ return Sema::AR_inaccessible;
+ }
+
+ // Same thing for function templates.
+ if (isa<FunctionTemplateDecl>(D)) {
+ if (!EC.Function) return Sema::AR_inaccessible;
+
+ FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate();
+ if (!FTD)
+ FTD = EC.Function->getDescribedFunctionTemplate();
+
+ if (FTD && D == FTD->getCanonicalDecl())
+ return Sema::AR_accessible;
+
+ return Sema::AR_inaccessible;
+ }
+
+ // Friend functions. FIXME: close matches due to dependency.
+ //
+ // The decl pointers in EC have been canonicalized, so pointer
+ // equality is sufficient.
+ if (D == EC.Function)
+ return Sema::AR_accessible;
+
+ if (isa<CXXRecordDecl>(D))
+ return MatchesFriend(S, EC, cast<CXXRecordDecl>(D));
+
+ return Sema::AR_inaccessible;
+}
+
static Sema::AccessResult GetFriendKind(Sema &S,
const EffectiveContext &EC,
const CXXRecordDecl *Class) {
// A class always has access to its own members.
- if (EC.isClass(Class))
+ if (EC.includesClass(Class))
return Sema::AR_accessible;
+ Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+
// Okay, check friends.
for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
E = Class->friend_end(); I != E; ++I) {
FriendDecl *Friend = *I;
- if (Type *T = Friend->getFriendType()) {
- if (EC.Record &&
- S.Context.hasSameType(QualType(T, 0),
- S.Context.getTypeDeclType(EC.Record)))
- return Sema::AR_accessible;
- } else {
- NamedDecl *D
- = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
+ switch (MatchesFriend(S, EC, Friend)) {
+ case Sema::AR_accessible:
+ return Sema::AR_accessible;
- // The decl pointers in EC have been canonicalized, so pointer
- // equality is sufficient.
- if (D == EC.Function || D == EC.Record)
- return Sema::AR_accessible;
- }
+ case Sema::AR_inaccessible:
+ break;
+
+ case Sema::AR_dependent:
+ OnFailure = Sema::AR_dependent;
+ break;
- // FIXME: templates! templated contexts! dependent delay!
+ case Sema::AR_delayed:
+ llvm_unreachable("cannot get delayed answer from MatchesFriend");
+ }
}
// That's it, give up.
- return Sema::AR_inaccessible;
+ return OnFailure;
}
/// Finds the best path from the naming class to the declaring class,
/// taking friend declarations into account.
///
+/// \param FinalAccess the access of the "final step", or AS_none if
+/// there is no final step.
/// \return null if friendship is dependent
static CXXBasePath *FindBestPath(Sema &S,
const EffectiveContext &EC,
CXXRecordDecl *Derived,
CXXRecordDecl *Base,
+ AccessSpecifier FinalAccess,
CXXBasePaths &Paths) {
// Derive the paths to the desired base.
bool isDerived = Derived->isDerivedFrom(Base, Paths);
@@ -133,28 +228,43 @@ static CXXBasePath *FindBestPath(Sema &S,
CXXBasePath *BestPath = 0;
+ assert(FinalAccess != AS_none && "forbidden access after declaring class");
+
// Derive the friend-modified access along each path.
for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
PI != PE; ++PI) {
// Walk through the path backwards.
- AccessSpecifier PathAccess = AS_public;
+ AccessSpecifier PathAccess = FinalAccess;
CXXBasePath::iterator I = PI->end(), E = PI->begin();
while (I != E) {
--I;
+ assert(PathAccess != AS_none);
+
+ // If the declaration is a private member of a base class, there
+ // is no level of friendship in derived classes that can make it
+ // accessible.
+ if (PathAccess == AS_private) {
+ PathAccess = AS_none;
+ break;
+ }
+
AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
if (BaseAccess != AS_public) {
switch (GetFriendKind(S, EC, I->Class)) {
- case Sema::AR_inaccessible: break;
- case Sema::AR_accessible: BaseAccess = AS_public; break;
- case Sema::AR_dependent: return 0;
+ case Sema::AR_inaccessible:
+ PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
+ break;
+ case Sema::AR_accessible:
+ PathAccess = AS_public;
+ break;
+ case Sema::AR_dependent:
+ return 0;
case Sema::AR_delayed:
llvm_unreachable("friend resolution is never delayed"); break;
}
}
-
- PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
}
// Note that we modify the path's Access field to the
@@ -199,7 +309,8 @@ static void DiagnoseAccessPath(Sema &S,
}
CXXBasePaths Paths;
- CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths);
+ CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass,
+ AS_public, Paths);
CXXBasePath::iterator I = Path.end(), E = Path.begin();
while (I != E) {
@@ -304,7 +415,7 @@ static void TryElevateAccess(Sema &S,
CXXRecordDecl *NamingClass = Entity.getNamingClass();
// Adjust the declaration of the referred entity.
- AccessSpecifier DeclAccess = AS_none;
+ AccessSpecifier DeclAccess = AS_public;
if (Entity.isMemberAccess()) {
NamedDecl *Target = Entity.getTargetDecl();
@@ -329,17 +440,15 @@ static void TryElevateAccess(Sema &S,
// Append the declaration's access if applicable.
CXXBasePaths Paths;
CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
- DeclaringClass, Paths);
+ DeclaringClass, DeclAccess, Paths);
if (!Path) {
// FIXME: delay dependent friendship
return;
}
- // Grab the access along the best path.
+ // Grab the access along the best path (note that this includes the
+ // final-step access).
AccessSpecifier NewAccess = Path->Access;
- if (Entity.isMemberAccess())
- NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess);
-
assert(NewAccess <= Access && "access along best path worse than direct?");
Access = NewAccess;
}
@@ -350,51 +459,38 @@ static Sema::AccessResult CheckEffectiveAccess(Sema &S,
SourceLocation Loc,
Sema::AccessedEntity const &Entity) {
AccessSpecifier Access = Entity.getAccess();
- assert(Access != AS_public);
+ assert(Access != AS_public && "called for public access!");
+ // Find a non-anonymous naming class. For records with access,
+ // there should always be one of these.
CXXRecordDecl *NamingClass = Entity.getNamingClass();
while (NamingClass->isAnonymousStructOrUnion())
- // This should be guaranteed by the fact that the decl has
- // non-public access. If not, we should make it guaranteed!
NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
- if (!EC.Record) {
- TryElevateAccess(S, EC, Entity, Access);
- if (Access == AS_public) return Sema::AR_accessible;
-
- if (!Entity.isQuiet())
- DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
- return Sema::AR_inaccessible;
- }
-
- // White-list accesses from within the declaring class.
- if (Access != AS_none && EC.isClass(NamingClass))
+ // White-list accesses from classes with privileges equivalent to the
+ // naming class --- but only if the access path isn't forbidden
+ // (i.e. an access of a private member from a subclass).
+ if (Access != AS_none && EC.includesClass(NamingClass))
return Sema::AR_accessible;
-
- // If the access is worse than 'protected', try to promote to it using
- // friend declarations.
- bool TriedElevation = false;
- if (Access != AS_protected) {
- TryElevateAccess(S, EC, Entity, Access);
- if (Access == AS_public) return Sema::AR_accessible;
- TriedElevation = true;
- }
+
+ // Try to elevate access.
+ // FIXME: delay if elevation was dependent?
+ // TODO: on some code, it might be better to do the protected check
+ // without trying to elevate first.
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
// Protected access.
if (Access == AS_protected) {
// FIXME: implement [class.protected]p1
- if (EC.Record->isDerivedFrom(NamingClass))
- return Sema::AR_accessible;
+ for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
+ I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I)
+ if ((*I)->isDerivedFrom(NamingClass))
+ return Sema::AR_accessible;
- // FIXME: delay dependent classes
+ // FIXME: delay if we can't decide class derivation yet.
}
- // We're about to reject; one last chance to promote access.
- if (!TriedElevation) {
- TryElevateAccess(S, EC, Entity, Access);
- if (Access == AS_public) return Sema::AR_accessible;
- }
-
// Okay, that's it, reject it.
if (!Entity.isQuiet())
DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
@@ -431,15 +527,13 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
}
Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
- NamedDecl *D,
- AccessSpecifier Access) {
+ DeclAccessPair Found) {
if (!getLangOptions().AccessControl ||
!E->getNamingClass() ||
- Access == AS_public)
+ Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(AccessedEntity::Member,
- E->getNamingClass(), Access, D);
+ AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getNameLoc(), Entity);
@@ -448,14 +542,12 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
/// Perform access-control checking on a previously-unresolved member
/// access which has now been resolved to a member.
Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
- NamedDecl *D,
- AccessSpecifier Access) {
+ DeclAccessPair Found) {
if (!getLangOptions().AccessControl ||
- Access == AS_public)
+ Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(AccessedEntity::Member,
- E->getNamingClass(), Access, D);
+ AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getMemberLoc(), Entity);
@@ -473,7 +565,8 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
return AR_accessible;
CXXRecordDecl *NamingClass = Dtor->getParent();
- AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor);
+ AccessedEntity Entity(AccessedEntity::Member, NamingClass,
+ DeclAccessPair::make(Dtor, Access));
Entity.setDiag(PDiag); // TODO: avoid copy
return CheckAccess(*this, Loc, Entity);
@@ -488,8 +581,8 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
- AccessedEntity Entity(AccessedEntity::Member,
- NamingClass, Access, Constructor);
+ AccessedEntity Entity(AccessedEntity::Member, NamingClass,
+ DeclAccessPair::make(Constructor, Access));
Entity.setDiag(diag::err_access_ctor);
return CheckAccess(*this, UseLoc, Entity);
@@ -506,29 +599,45 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
return AR_accessible;
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
- AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target);
+ AccessedEntity Entity(AccessedEntity::Member, NamingClass,
+ DeclAccessPair::make(Target, Access));
Entity.setDiag(Diag);
return CheckAccess(*this, UseLoc, Entity);
}
+/// Checks access to an overloaded operator new or delete.
+Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
+ SourceRange PlacementRange,
+ CXXRecordDecl *NamingClass,
+ DeclAccessPair Found) {
+ if (!getLangOptions().AccessControl ||
+ !NamingClass ||
+ Found.getAccess() == AS_public)
+ return AR_accessible;
+
+ AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
+ Entity.setDiag(diag::err_access)
+ << PlacementRange;
+
+ return CheckAccess(*this, OpLoc, Entity);
+}
+
/// Checks access to an overloaded member operator, including
/// conversion operators.
Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
Expr *ObjectExpr,
Expr *ArgExpr,
- NamedDecl *MemberOperator,
- AccessSpecifier Access) {
+ DeclAccessPair Found) {
if (!getLangOptions().AccessControl ||
- Access == AS_public)
+ Found.getAccess() == AS_public)
return AR_accessible;
const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
assert(RT && "found member operator but object expr not of record type");
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
- AccessedEntity Entity(AccessedEntity::Member,
- NamingClass, Access, MemberOperator);
+ AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
Entity.setDiag(diag::err_access)
<< ObjectExpr->getSourceRange()
<< (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
@@ -580,7 +689,8 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (I.getAccess() != AS_public) {
AccessedEntity Entity(AccessedEntity::Member,
- R.getNamingClass(), I.getAccess(), *I);
+ R.getNamingClass(),
+ I.getPair());
Entity.setDiag(diag::err_access);
CheckAccess(*this, R.getNameLoc(), Entity);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 3fac79deba4b..0a33485dd777 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -13,9 +13,6 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/PrintfFormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
@@ -30,7 +27,6 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include <limits>
-#include <queue>
using namespace clang;
/// getLocationOfStringLiteralByte - Return a source location that points to the
@@ -2045,6 +2041,11 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
if (!tmp.isNull()) rt = tmp;
}
+ if (const EnumType *E = lt->getAs<EnumType>())
+ lt = E->getDecl()->getPromotionType();
+ if (const EnumType *E = rt->getAs<EnumType>())
+ rt = E->getDecl()->getPromotionType();
+
// The rule is that the signed operand becomes unsigned, so isolate the
// signed operand.
Expr *signedOperand = lex, *unsignedOperand = rex;
@@ -2219,276 +2220,6 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
return;
}
-
-
-namespace {
-class UnreachableCodeHandler : public reachable_code::Callback {
- Sema &S;
-public:
- UnreachableCodeHandler(Sema *s) : S(*s) {}
-
- void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) {
- S.Diag(L, diag::warn_unreachable) << R1 << R2;
- }
-};
-}
-
-/// CheckUnreachable - Check for unreachable code.
-void Sema::CheckUnreachable(AnalysisContext &AC) {
- // We avoid checking when there are errors, as the CFG won't faithfully match
- // the user's code.
- if (getDiagnostics().hasErrorOccurred() ||
- Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
- return;
-
- UnreachableCodeHandler UC(this);
- reachable_code::FindUnreachableCode(AC, UC);
-}
-
-/// CheckFallThrough - Check that we don't fall off the end of a
-/// Statement that should return a value.
-///
-/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
-/// MaybeFallThrough iff we might or might not fall off the end,
-/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
-/// return. We assume NeverFallThrough iff we never fall off the end of the
-/// statement but we may return. We assume that functions not marked noreturn
-/// will return.
-Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
- CFG *cfg = AC.getCFG();
- if (cfg == 0)
- // FIXME: This should be NeverFallThrough
- return NeverFallThroughOrReturn;
-
- // The CFG leaves in dead things, and we don't want the dead code paths to
- // confuse us, so we mark all live things first.
- std::queue<CFGBlock*> workq;
- llvm::BitVector live(cfg->getNumBlockIDs());
- unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(),
- live);
-
- bool AddEHEdges = AC.getAddEHEdges();
- if (!AddEHEdges && count != cfg->getNumBlockIDs())
- // When there are things remaining dead, and we didn't add EH edges
- // from CallExprs to the catch clauses, we have to go back and
- // mark them as live.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!live[b.getBlockID()]) {
- if (b.pred_begin() == b.pred_end()) {
- if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator()))
- // When not adding EH edges from calls, catch clauses
- // can otherwise seem dead. Avoid noting them as dead.
- count += reachable_code::ScanReachableFromBlock(b, live);
- continue;
- }
- }
- }
-
- // Now we know what is live, we check the live precessors of the exit block
- // and look for fall through paths, being careful to ignore normal returns,
- // and exceptional paths.
- bool HasLiveReturn = false;
- bool HasFakeEdge = false;
- bool HasPlainEdge = false;
- bool HasAbnormalEdge = false;
- for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(),
- E = cfg->getExit().pred_end();
- I != E;
- ++I) {
- CFGBlock& B = **I;
- if (!live[B.getBlockID()])
- continue;
- if (B.size() == 0) {
- if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
- HasAbnormalEdge = true;
- continue;
- }
-
- // A labeled empty statement, or the entry block...
- HasPlainEdge = true;
- continue;
- }
- Stmt *S = B[B.size()-1];
- if (isa<ReturnStmt>(S)) {
- HasLiveReturn = true;
- continue;
- }
- if (isa<ObjCAtThrowStmt>(S)) {
- HasFakeEdge = true;
- continue;
- }
- if (isa<CXXThrowExpr>(S)) {
- HasFakeEdge = true;
- continue;
- }
- if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
- if (AS->isMSAsm()) {
- HasFakeEdge = true;
- HasLiveReturn = true;
- continue;
- }
- }
- if (isa<CXXTryStmt>(S)) {
- HasAbnormalEdge = true;
- continue;
- }
-
- bool NoReturnEdge = false;
- if (CallExpr *C = dyn_cast<CallExpr>(S)) {
- if (B.succ_begin()[0] != &cfg->getExit()) {
- HasAbnormalEdge = true;
- continue;
- }
- Expr *CEE = C->getCallee()->IgnoreParenCasts();
- if (CEE->getType().getNoReturnAttr()) {
- NoReturnEdge = true;
- HasFakeEdge = true;
- } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
- ValueDecl *VD = DRE->getDecl();
- if (VD->hasAttr<NoReturnAttr>()) {
- NoReturnEdge = true;
- HasFakeEdge = true;
- }
- }
- }
- // FIXME: Add noreturn message sends.
- if (NoReturnEdge == false)
- HasPlainEdge = true;
- }
- if (!HasPlainEdge) {
- if (HasLiveReturn)
- return NeverFallThrough;
- return NeverFallThroughOrReturn;
- }
- if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
- return MaybeFallThrough;
- // This says AlwaysFallThrough for calls to functions that are not marked
- // noreturn, that don't return. If people would like this warning to be more
- // accurate, such functions should be marked as noreturn.
- return AlwaysFallThrough;
-}
-
-/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
-/// function that should return a value. Check that we don't fall off the end
-/// of a noreturn function. We assume that functions and blocks not marked
-/// noreturn will return.
-void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
- AnalysisContext &AC) {
- // FIXME: Would be nice if we had a better way to control cascading errors,
- // but for now, avoid them. The problem is that when Parse sees:
- // int foo() { return a; }
- // The return is eaten and the Sema code sees just:
- // int foo() { }
- // which this code would then warn about.
- if (getDiagnostics().hasErrorOccurred())
- return;
-
- bool ReturnsVoid = false;
- bool HasNoReturn = false;
-
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // For function templates, class templates and member function templates
- // we'll do the analysis at instantiation time.
- if (FD->isDependentContext())
- return;
-
- ReturnsVoid = FD->getResultType()->isVoidType();
- HasNoReturn = FD->hasAttr<NoReturnAttr>() ||
- FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
-
- } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- ReturnsVoid = MD->getResultType()->isVoidType();
- HasNoReturn = MD->hasAttr<NoReturnAttr>();
- }
-
- // Short circuit for compilation speed.
- if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
- == Diagnostic::Ignored || ReturnsVoid)
- && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
- == Diagnostic::Ignored || !HasNoReturn)
- && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
- == Diagnostic::Ignored || !ReturnsVoid))
- return;
- // FIXME: Function try block
- if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(AC)) {
- case MaybeFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function);
- break;
- case AlwaysFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
- break;
- case NeverFallThroughOrReturn:
- if (ReturnsVoid && !HasNoReturn)
- Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
- break;
- case NeverFallThrough:
- break;
- }
- }
-}
-
-/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
-/// that should return a value. Check that we don't fall off the end of a
-/// noreturn block. We assume that functions and blocks not marked noreturn
-/// will return.
-void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body,
- AnalysisContext &AC) {
- // FIXME: Would be nice if we had a better way to control cascading errors,
- // but for now, avoid them. The problem is that when Parse sees:
- // int foo() { return a; }
- // The return is eaten and the Sema code sees just:
- // int foo() { }
- // which this code would then warn about.
- if (getDiagnostics().hasErrorOccurred())
- return;
- bool ReturnsVoid = false;
- bool HasNoReturn = false;
- if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){
- if (FT->getResultType()->isVoidType())
- ReturnsVoid = true;
- if (FT->getNoReturnAttr())
- HasNoReturn = true;
- }
-
- // Short circuit for compilation speed.
- if (ReturnsVoid
- && !HasNoReturn
- && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
- == Diagnostic::Ignored || !ReturnsVoid))
- return;
- // FIXME: Funtion try block
- if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(AC)) {
- case MaybeFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
- break;
- case AlwaysFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
- break;
- case NeverFallThroughOrReturn:
- if (ReturnsVoid)
- Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
- break;
- case NeverFallThrough:
- break;
- }
- }
-}
-
/// CheckParmsForFunctionDef - Check that the parameters of the given
/// function are appropriate for the definition of a function. This
/// takes care of any checks that cannot be performed on the
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 4693fa974edb..317eef8d60fc 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2253,7 +2253,8 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
Results.push_back(ResultCandidate(FDecl));
else
// FIXME: access?
- AddOverloadCandidate(FDecl, AS_none, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(FDecl, DeclAccessPair::make(FDecl, AS_none),
+ Args, NumArgs, CandidateSet,
false, false, /*PartialOverloading*/ true);
}
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index dab7d883a1d6..e11e161ffde2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -14,7 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "AnalysisBasedWarnings.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -2403,6 +2403,10 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
NewVD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString()));
}
+ // Diagnose shadowed variables before filtering for scope.
+ if (!D.getCXXScopeSpec().isSet())
+ DiagnoseShadow(S, D, Previous);
+
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
@@ -2454,6 +2458,72 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
return NewVD;
}
+/// \brief Diagnose variable or built-in function shadowing.
+///
+/// This method is called as soon as a NamedDecl materializes to check
+/// if it shadows another local or global variable, or a built-in function.
+///
+/// For performance reasons, the lookup results are reused from the calling
+/// context.
+///
+/// \param S the scope in which the shadowing name is being declared
+/// \param R the lookup of the name
+///
+void Sema::DiagnoseShadow(Scope *S, Declarator &D,
+ const LookupResult& R) {
+ // Return if warning is ignored.
+ if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored)
+ return;
+
+ // Don't diagnose declarations at file scope. The scope might not
+ // have a DeclContext if (e.g.) we're parsing a function prototype.
+ DeclContext *NewDC = static_cast<DeclContext*>(S->getEntity());
+ if (NewDC && NewDC->isFileContext())
+ return;
+
+ // Only diagnose if we're shadowing an unambiguous field or variable.
+ if (R.getResultKind() != LookupResult::Found)
+ return;
+
+ NamedDecl* ShadowedDecl = R.getFoundDecl();
+ if (!isa<VarDecl>(ShadowedDecl) && !isa<FieldDecl>(ShadowedDecl))
+ return;
+
+ DeclContext *OldDC = ShadowedDecl->getDeclContext();
+
+ // Only warn about certain kinds of shadowing for class members.
+ if (NewDC && NewDC->isRecord()) {
+ // In particular, don't warn about shadowing non-class members.
+ if (!OldDC->isRecord())
+ return;
+
+ // TODO: should we warn about static data members shadowing
+ // static data members from base classes?
+
+ // TODO: don't diagnose for inaccessible shadowed members.
+ // This is hard to do perfectly because we might friend the
+ // shadowing context, but that's just a false negative.
+ }
+
+ // Determine what kind of declaration we're shadowing.
+ unsigned Kind;
+ if (isa<RecordDecl>(OldDC)) {
+ if (isa<FieldDecl>(ShadowedDecl))
+ Kind = 3; // field
+ else
+ Kind = 2; // static data member
+ } else if (OldDC->isFileContext())
+ Kind = 1; // global
+ else
+ Kind = 0; // local
+
+ DeclarationName Name = R.getLookupName();
+
+ // Emit warning and note.
+ Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC;
+ Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
+}
+
/// \brief Perform semantic checking on a newly-created variable
/// declaration.
///
@@ -3896,7 +3966,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Check for redeclaration of parameters, e.g. int foo(int x, int x);
IdentifierInfo *II = D.getIdentifier();
if (II) {
- if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) {
+ LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName,
+ ForRedeclaration);
+ LookupName(R, S);
+ if (R.isSingleResult()) {
+ NamedDecl *PrevDecl = R.getFoundDecl();
if (PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
@@ -3910,6 +3984,8 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
II = 0;
D.SetIdentifier(0, D.getIdentifierLoc());
D.setInvalidType(true);
+ } else {
+ DiagnoseShadow(S, D, R);
}
}
}
@@ -4183,9 +4259,6 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
Decl *dcl = D.getAs<Decl>();
Stmt *Body = BodyArg.takeAs<Stmt>();
- // Don't generate EH edges for CallExprs as we'd like to avoid the n^2
- // explosion for destrutors that can result and the compile time hit.
- AnalysisContext AC(dcl, false);
FunctionDecl *FD = 0;
FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
if (FunTmpl)
@@ -4193,14 +4266,16 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
else
FD = dyn_cast_or_null<FunctionDecl>(dcl);
+ sema::AnalysisBasedWarnings W(*this);
+
if (FD) {
FD->setBody(Body);
- if (FD->isMain())
+ if (FD->isMain()) {
// C and C++ allow for main to automagically return 0.
// Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
FD->setHasImplicitReturnZero(true);
- else
- CheckFallThroughForFunctionDef(FD, Body, AC);
+ W.disableCheckFallThrough();
+ }
if (!FD->isInvalidDecl())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
@@ -4212,9 +4287,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
- CheckFallThroughForFunctionDef(MD, Body, AC);
MD->setEndLoc(Body->getLocEnd());
-
if (!MD->isInvalidDecl())
DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
} else {
@@ -4267,28 +4340,40 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
}
if (Body) {
- CheckUnreachable(AC);
-
// C++ constructors that have function-try-blocks can't have return
// statements in the handlers of that block. (C++ [except.handle]p14)
// Verify this.
if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
- // Verify that that gotos and switch cases don't jump into scopes illegally.
- // Verify that that gotos and switch cases don't jump into scopes illegally.
+ // Verify that that gotos and switch cases don't jump into scopes illegally.
+ // Verify that that gotos and switch cases don't jump into scopes illegally.
if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction())
DiagnoseInvalidJumps(Body);
if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
- MarkBaseAndMemberDestructorsReferenced(Destructor);
+ MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
+ Destructor->getParent());
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
if (PP.getDiagnostics().hasErrorOccurred())
ExprTemporaries.clear();
-
+ else if (!isa<FunctionTemplateDecl>(dcl)) {
+ // Since the body is valid, issue any analysis-based warnings that are
+ // enabled.
+ QualType ResultType;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(dcl)) {
+ ResultType = FD->getResultType();
+ }
+ else {
+ ObjCMethodDecl *MD = cast<ObjCMethodDecl>(dcl);
+ ResultType = MD->getResultType();
+ }
+ W.IssueWarnings(dcl);
+ }
+
assert(ExprTemporaries.empty() && "Leftover temporaries in function");
}
@@ -5055,6 +5140,18 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
Consumer.HandleTagDeclDefinition(Tag);
}
+void Sema::ActOnTagDefinitionError(Scope *S, DeclPtrTy TagD) {
+ AdjustDeclIfTemplate(TagD);
+ TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
+ Tag->setInvalidDecl();
+
+ // We're undoing ActOnTagStartDefinition here, not
+ // ActOnStartCXXMemberDeclarations, so we don't have to mess with
+ // the FieldCollector.
+
+ PopDeclContext();
+}
+
// Note that FieldName may be null for anonymous bitfields.
bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
QualType FieldTy, const Expr *BitWidth,
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index c27b0d5013c6..13a7ead76bdf 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1643,29 +1643,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
Constructor->setNumBaseOrMemberInitializers(NumInitializers);
CXXBaseOrMemberInitializer **baseOrMemberInitializers =
new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
-
+ memcpy(baseOrMemberInitializers, AllToInit.data(),
+ NumInitializers * sizeof(CXXBaseOrMemberInitializer*));
Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
- for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) {
- CXXBaseOrMemberInitializer *Member = AllToInit[Idx];
- baseOrMemberInitializers[Idx] = Member;
- if (!Member->isBaseInitializer())
- continue;
- const Type *BaseType = Member->getBaseClass();
- const RecordType *RT = BaseType->getAs<RecordType>();
- if (!RT)
- continue;
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(RT->getDecl());
-
- // We don't know if a dependent type will have an implicit destructor.
- if (BaseClassDecl->isDependentType())
- continue;
- if (BaseClassDecl->hasTrivialDestructor())
- continue;
- CXXDestructorDecl *DD = BaseClassDecl->getDestructor(Context);
- MarkDeclarationReferenced(Constructor->getLocation(), DD);
- }
+ // Constructors implicitly reference the base and member
+ // destructors.
+ MarkBaseAndMemberDestructorsReferenced(Constructor->getLocation(),
+ Constructor->getParent());
}
return HadError;
@@ -1848,9 +1833,10 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
}
void
-Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
- // Ignore dependent destructors.
- if (Destructor->isDependentContext())
+Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
+ CXXRecordDecl *ClassDecl) {
+ // Ignore dependent contexts.
+ if (ClassDecl->isDependentContext())
return;
// FIXME: all the access-control diagnostics are positioned on the
@@ -1858,8 +1844,6 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
// user might reasonably want to know why the destructor is being
// emitted, and we currently don't say.
- CXXRecordDecl *ClassDecl = Destructor->getParent();
-
// Non-static data members.
for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
E = ClassDecl->field_end(); I != E; ++I) {
@@ -1881,8 +1865,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
<< Field->getDeclName()
<< FieldType);
- MarkDeclarationReferenced(Destructor->getLocation(),
- const_cast<CXXDestructorDecl*>(Dtor));
+ MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
}
llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
@@ -1910,8 +1893,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
<< Base->getType()
<< Base->getSourceRange());
- MarkDeclarationReferenced(Destructor->getLocation(),
- const_cast<CXXDestructorDecl*>(Dtor));
+ MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
}
// Virtual bases.
@@ -1935,8 +1917,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
PartialDiagnostic(diag::err_access_dtor_vbase)
<< VBase->getType());
- MarkDeclarationReferenced(Destructor->getLocation(),
- const_cast<CXXDestructorDecl*>(Dtor));
+ MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
}
}
@@ -3819,7 +3800,8 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
DeclContext *PreviousContext = CurContext;
CurContext = Destructor;
- MarkBaseAndMemberDestructorsReferenced(Destructor);
+ MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
+ Destructor->getParent());
// FIXME: If CheckDestructor fails, we should emit a note about where the
// implicit destructor was needed.
@@ -4222,6 +4204,8 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef,
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
+ DeclAccessPair FoundDecl = DeclAccessPair::make(*Con, (*Con)->getAccess());
+
// Find the constructor (which may be a template).
CXXConstructorDecl *Constructor = 0;
FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
@@ -4238,12 +4222,11 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef,
((Kind.getKind() == InitializationKind::IK_Default) &&
Constructor->isDefaultConstructor())) {
if (ConstructorTmpl)
- SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl,
- ConstructorTmpl->getAccess(),
+ SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
else
- SemaRef.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ SemaRef.AddOverloadCandidate(Constructor, FoundDecl,
Args, NumArgs, CandidateSet);
}
}
@@ -4553,10 +4536,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (Conv->getConversionType()->isLValueReferenceType() &&
(AllowExplicit || !Conv->isExplicit())) {
if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), ActingDC,
+ AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
Init, DeclType, CandidateSet);
else
- AddConversionCandidate(Conv, I.getAccess(), ActingDC, Init,
+ AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
DeclType, CandidateSet);
}
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index a39ba2f7d06e..fe6f3b9f5607 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -14,7 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "AnalysisBasedWarnings.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -1691,7 +1691,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
return ExprError();
}
- if (VD->getType()->isArrayType() && !VD->hasAttr<BlocksAttr>()) {
+ if (VD->getType()->isArrayType()) {
Diag(Loc, diag::err_ref_array_type);
Diag(D->getLocation(), diag::note_declared_at);
return ExprError();
@@ -1751,7 +1751,10 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
llvm::SmallString<16> CharBuffer;
- llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer);
+ bool Invalid = false;
+ llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid);
+ if (Invalid)
+ return ExprError();
CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), Tok.getLocation(),
PP);
@@ -1789,7 +1792,10 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
const char *ThisTokBegin = &IntegerBuffer[0];
// Get the spelling of the token, which eliminates trigraphs, etc.
- unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
+ bool Invalid = false;
+ unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid);
+ if (Invalid)
+ return ExprError();
NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
Tok.getLocation(), PP);
@@ -4573,7 +4579,11 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
if (lhptee.getLocalCVRQualifiers() != rhptee.getLocalCVRQualifiers())
ConvTy = CompatiblePointerDiscardsQualifiers;
- if (!Context.typesAreCompatible(lhptee, rhptee))
+ if (!getLangOptions().CPlusPlus) {
+ if (!Context.typesAreBlockPointerCompatible(lhsType, rhsType))
+ return IncompatibleBlockPointer;
+ }
+ else if (!Context.typesAreCompatible(lhptee, rhptee))
return IncompatibleBlockPointer;
return ConvTy;
}
@@ -4582,8 +4592,18 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
/// for assignment compatibility.
Sema::AssignConvertType
Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
- if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType())
+ if (lhsType->isObjCBuiltinType()) {
+ // Class is not compatible with ObjC object pointers.
+ if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType())
+ return IncompatiblePointer;
+ return Compatible;
+ }
+ if (rhsType->isObjCBuiltinType()) {
+ // Class is not compatible with ObjC object pointers.
+ if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType())
+ return IncompatiblePointer;
return Compatible;
+ }
QualType lhptee =
lhsType->getAs<ObjCObjectPointerType>()->getPointeeType();
QualType rhptee =
@@ -5780,9 +5800,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_SubObjCPropertySetting:
Diag = diag::error_no_subobject_property_setting;
break;
- case Expr::MLV_SubObjCPropertyGetterSetting:
- Diag = diag::error_no_subobject_property_getter_setting;
- break;
}
SourceRange Assign;
@@ -6986,9 +7003,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
return ExprError();
}
- AnalysisContext AC(BSI->TheDecl);
- CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
- CheckUnreachable(AC);
+ // Issue any analysis-based warnings.
+ sema::AnalysisBasedWarnings W(*this);
+ W.IssueWarnings(BSI->TheDecl, BlockTy);
+
Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs);
PopFunctionOrBlockScope();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index e1e5efa7d3a9..366089f2ab63 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -912,6 +912,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
= cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl());
LookupQualifiedName(FoundDelete, RD);
}
+ if (FoundDelete.isAmbiguous())
+ return true; // FIXME: clean up expressions?
if (FoundDelete.empty()) {
DeclareGlobalNewDelete();
@@ -919,8 +921,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
}
FoundDelete.suppressDiagnostics();
- llvm::SmallVector<NamedDecl *, 4> Matches;
- if (NumPlaceArgs > 1) {
+
+ llvm::SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches;
+
+ if (NumPlaceArgs > 0) {
// C++ [expr.new]p20:
// A declaration of a placement deallocation function matches the
// declaration of a placement allocation function if it has the
@@ -962,7 +966,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl());
if (Context.hasSameType(Fn->getType(), ExpectedFunctionType))
- Matches.push_back(Fn);
+ Matches.push_back(std::make_pair(D.getPair(), Fn));
}
} else {
// C++ [expr.new]p20:
@@ -973,7 +977,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
D != DEnd; ++D) {
if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl()))
if (isNonPlacementDeallocationFunction(Fn))
- Matches.push_back(*D);
+ Matches.push_back(std::make_pair(D.getPair(), Fn));
}
}
@@ -982,8 +986,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// function, that function will be called; otherwise, no
// deallocation function will be called.
if (Matches.size() == 1) {
- // FIXME: Drops access, using-declaration info!
- OperatorDelete = cast<FunctionDecl>(Matches[0]->getUnderlyingDecl());
+ OperatorDelete = Matches[0].second;
// C++0x [expr.new]p20:
// If the lookup finds the two-parameter form of a usual
@@ -998,6 +1001,9 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
PlaceArgs[NumPlaceArgs - 1]->getLocEnd());
Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
<< DeleteName;
+ } else {
+ CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(),
+ Matches[0].first);
}
}
@@ -1019,25 +1025,28 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
<< Name << Range;
}
- // FIXME: handle ambiguity
+ if (R.isAmbiguous())
+ return true;
+
+ R.suppressDiagnostics();
OverloadCandidateSet Candidates(StartLoc);
for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
Alloc != AllocEnd; ++Alloc) {
// Even member operator new/delete are implicitly treated as
// static, so don't use AddMemberCandidate.
+ NamedDecl *D = (*Alloc)->getUnderlyingDecl();
- if (FunctionTemplateDecl *FnTemplate =
- dyn_cast<FunctionTemplateDecl>((*Alloc)->getUnderlyingDecl())) {
- AddTemplateOverloadCandidate(FnTemplate, Alloc.getAccess(),
+ if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) {
+ AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(),
/*ExplicitTemplateArgs=*/0, Args, NumArgs,
Candidates,
/*SuppressUserConversions=*/false);
continue;
}
- FunctionDecl *Fn = cast<FunctionDecl>((*Alloc)->getUnderlyingDecl());
- AddOverloadCandidate(Fn, Alloc.getAccess(), Args, NumArgs, Candidates,
+ FunctionDecl *Fn = cast<FunctionDecl>(D);
+ AddOverloadCandidate(Fn, Alloc.getPair(), Args, NumArgs, Candidates,
/*SuppressUserConversions=*/false);
}
@@ -1050,7 +1059,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// The first argument is size_t, and the first parameter must be size_t,
// too. This is checked on declaration and can be assumed. (It can't be
// asserted on, though, since invalid decls are left in there.)
- // Whatch out for variadic allocator function.
+ // Watch out for variadic allocator function.
unsigned NumArgsInFnDecl = FnDecl->getNumParams();
for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) {
if (PerformCopyInitialization(Args[i],
@@ -1059,6 +1068,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
return true;
}
Operator = FnDecl;
+ CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl);
return false;
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 98a7eec232f6..f86ae51c2806 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2007,7 +2007,8 @@ void InitializationSequence::AddAddressOverloadResolutionStep(
S.Kind = SK_ResolveAddressOfOverloadedFunction;
S.Type = Function->getType();
// Access is currently ignored for these.
- S.Function = DeclAccessPair::make(Function, AccessSpecifier(0));
+ S.Function.Function = Function;
+ S.Function.FoundDecl = DeclAccessPair::make(Function, AS_none);
Steps.push_back(S);
}
@@ -2028,12 +2029,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T,
}
void InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
QualType T) {
Step S;
S.Kind = SK_UserConversion;
S.Type = T;
- S.Function = DeclAccessPair::make(Function, Access);
+ S.Function.Function = Function;
+ S.Function.FoundDecl = FoundDecl;
Steps.push_back(S);
}
@@ -2071,7 +2073,8 @@ InitializationSequence::AddConstructorInitializationStep(
Step S;
S.Kind = SK_ConstructorInitialization;
S.Type = T;
- S.Function = DeclAccessPair::make(Constructor, Access);
+ S.Function.Function = Constructor;
+ S.Function.FoundDecl = DeclAccessPair::make(Constructor, Access);
Steps.push_back(S);
}
@@ -2198,25 +2201,26 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
DeclContext::lookup_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = T1RecordDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+
// Find the constructor (which may be a template).
CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl
- = dyn_cast<FunctionTemplateDecl>(*Con);
+ FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
Constructor = cast<CXXConstructorDecl>(
ConstructorTmpl->getTemplatedDecl());
else
- Constructor = cast<CXXConstructorDecl>(*Con);
+ Constructor = cast<CXXConstructorDecl>(D);
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl,
- ConstructorTmpl->getAccess(),
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
&Initializer, 1, CandidateSet);
else
- S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ S.AddOverloadCandidate(Constructor, FoundDecl,
&Initializer, 1, CandidateSet);
}
}
@@ -2257,11 +2261,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
if ((AllowExplicit || !Conv->isExplicit()) &&
(AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(),
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
ActingDC, Initializer,
ToType, CandidateSet);
else
- S.AddConversionCandidate(Conv, I.getAccess(), ActingDC,
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
Initializer, ToType, CandidateSet);
}
}
@@ -2284,7 +2288,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
T2 = cv1T1;
// Add the user-defined conversion step.
- Sequence.AddUserConversionStep(Function, Best->getAccess(),
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl,
T2.getNonReferenceType());
// Determine whether we need to perform derived-to-base or
@@ -2574,25 +2578,26 @@ static void TryConstructorInitialization(Sema &S,
DeclContext::lookup_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+
// Find the constructor (which may be a template).
CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl
- = dyn_cast<FunctionTemplateDecl>(*Con);
+ FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
Constructor = cast<CXXConstructorDecl>(
ConstructorTmpl->getTemplatedDecl());
else
- Constructor = cast<CXXConstructorDecl>(*Con);
+ Constructor = cast<CXXConstructorDecl>(D);
if (!Constructor->isInvalidDecl() &&
(AllowExplicit || !Constructor->isExplicit())) {
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl,
- ConstructorTmpl->getAccess(),
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
else
- S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ S.AddOverloadCandidate(Constructor, FoundDecl,
Args, NumArgs, CandidateSet);
}
}
@@ -2623,11 +2628,11 @@ static void TryConstructorInitialization(Sema &S,
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
if (Kind.getKind() == InitializationKind::IK_Copy) {
- Sequence.AddUserConversionStep(Best->Function, Best->getAccess(), DestType);
+ Sequence.AddUserConversionStep(Best->Function, Best->FoundDecl, DestType);
} else {
Sequence.AddConstructorInitializationStep(
cast<CXXConstructorDecl>(Best->Function),
- Best->getAccess(),
+ Best->FoundDecl.getAccess(),
DestType);
}
}
@@ -2744,25 +2749,27 @@ static void TryUserDefinedConversion(Sema &S,
DeclContext::lookup_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+
// Find the constructor (which may be a template).
CXXConstructorDecl *Constructor = 0;
FunctionTemplateDecl *ConstructorTmpl
- = dyn_cast<FunctionTemplateDecl>(*Con);
+ = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
Constructor = cast<CXXConstructorDecl>(
ConstructorTmpl->getTemplatedDecl());
else
- Constructor = cast<CXXConstructorDecl>(*Con);
+ Constructor = cast<CXXConstructorDecl>(D);
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl,
- ConstructorTmpl->getAccess(),
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
&Initializer, 1, CandidateSet);
else
- S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ S.AddOverloadCandidate(Constructor, FoundDecl,
&Initializer, 1, CandidateSet);
}
}
@@ -2799,11 +2806,11 @@ static void TryUserDefinedConversion(Sema &S,
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(),
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
ActingDC, Initializer, DestType,
CandidateSet);
else
- S.AddConversionCandidate(Conv, I.getAccess(), ActingDC,
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
Initializer, DestType, CandidateSet);
}
}
@@ -2825,13 +2832,13 @@ static void TryUserDefinedConversion(Sema &S,
if (isa<CXXConstructorDecl>(Function)) {
// Add the user-defined conversion step. Any cv-qualification conversion is
// subsumed by the initialization.
- Sequence.AddUserConversionStep(Function, Best->getAccess(), DestType);
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType);
return;
}
// Add the user-defined conversion step that calls the conversion function.
QualType ConvType = Function->getResultType().getNonReferenceType();
- Sequence.AddUserConversionStep(Function, Best->getAccess(), ConvType);
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType);
// If the conversion following the call to the conversion function is
// interesting, add it as a separate step.
@@ -3135,8 +3142,10 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
if (!Constructor || Constructor->isInvalidDecl() ||
!Constructor->isCopyConstructor())
continue;
-
- S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+
+ DeclAccessPair FoundDecl
+ = DeclAccessPair::make(Constructor, Constructor->getAccess());
+ S.AddOverloadCandidate(Constructor, FoundDecl,
&CurInitExpr, 1, CandidateSet);
}
@@ -3170,6 +3179,10 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
return S.ExprError();
}
+ S.CheckConstructorAccess(Loc,
+ cast<CXXConstructorDecl>(Best->Function),
+ Best->FoundDecl.getAccess());
+
CurInit.release();
return S.BuildCXXConstructExpr(Loc, CurInitExpr->getType(),
cast<CXXConstructorDecl>(Best->Function),
@@ -3303,7 +3316,7 @@ InitializationSequence::Perform(Sema &S,
// initializer to reflect that choice.
// Access control was done in overload resolution.
CurInit = S.FixOverloadedFunctionReference(move(CurInit),
- cast<FunctionDecl>(Step->Function.getDecl()));
+ Step->Function.Function);
break;
case SK_CastDerivedToBaseRValue:
@@ -3367,8 +3380,8 @@ InitializationSequence::Perform(Sema &S,
// or a conversion function.
CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
bool IsCopy = false;
- FunctionDecl *Fn = cast<FunctionDecl>(Step->Function.getDecl());
- AccessSpecifier FnAccess = Step->Function.getAccess();
+ FunctionDecl *Fn = Step->Function.Function;
+ DeclAccessPair FoundFn = Step->Function.FoundDecl;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
@@ -3390,7 +3403,8 @@ InitializationSequence::Perform(Sema &S,
if (CurInit.isInvalid())
return S.ExprError();
- S.CheckConstructorAccess(Kind.getLocation(), Constructor, FnAccess);
+ S.CheckConstructorAccess(Kind.getLocation(), Constructor,
+ FoundFn.getAccess());
CastKind = CastExpr::CK_ConstructorConversion;
QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
@@ -3402,7 +3416,7 @@ InitializationSequence::Perform(Sema &S,
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0,
- Conversion, FnAccess);
+ FoundFn);
// FIXME: Should we move this initialization into a separate
// derived-to-base conversion? I believe the answer is "no", because
@@ -3469,7 +3483,7 @@ InitializationSequence::Perform(Sema &S,
case SK_ConstructorInitialization: {
CXXConstructorDecl *Constructor
- = cast<CXXConstructorDecl>(Step->Function.getDecl());
+ = cast<CXXConstructorDecl>(Step->Function.Function);
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
@@ -3506,7 +3520,8 @@ InitializationSequence::Perform(Sema &S,
return S.ExprError();
// Only check access if all of that succeeded.
- S.CheckConstructorAccess(Loc, Constructor, Step->Function.getAccess());
+ S.CheckConstructorAccess(Loc, Constructor,
+ Step->Function.FoundDecl.getAccess());
bool Elidable
= cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable();
@@ -3972,7 +3987,8 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
break;
case SK_UserConversion:
- OS << "user-defined conversion via " << S->Function->getNameAsString();
+ OS << "user-defined conversion via "
+ << S->Function.Function->getNameAsString();
break;
case SK_QualificationConversionRValue:
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 2b49df28fe86..18a0938f7c09 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -454,7 +454,10 @@ public:
/// Always a FunctionDecl.
/// For conversion decls, the naming class is the source type.
/// For construct decls, the naming class is the target type.
- DeclAccessPair Function;
+ struct {
+ FunctionDecl *Function;
+ DeclAccessPair FoundDecl;
+ } Function;
/// \brief When Kind = SK_ConversionSequence, the implicit conversion
/// sequence
@@ -622,7 +625,7 @@ public:
/// \brief Add a new step invoking a conversion function, which is either
/// a constructor or a conversion function.
void AddUserConversionStep(FunctionDecl *Function,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
QualType T);
/// \brief Add a new step that performs a qualification conversion to the
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 6caeec620d01..9ae520d27a65 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -1176,7 +1176,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// FIXME: support using declarations!
QualType SubobjectType;
int SubobjectNumber = 0;
- AccessSpecifier SubobjectAccess = AS_private;
+ AccessSpecifier SubobjectAccess = AS_none;
for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
Path != PathEnd; ++Path) {
const CXXBasePathElement &PathElement = Path->back();
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 3a0fe0a61afe..41ed6c630cb2 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -137,17 +137,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
Diag(AtLoc, diag::warn_property_attr_mismatch);
Diag(PIDecl->getLocation(), diag::note_property_declare);
}
- DeclContext *DC = dyn_cast<DeclContext>(CCPrimary);
- assert(DC && "ClassDecl is not a DeclContext");
- DeclContext::lookup_result Found =
- DC->lookup(PIDecl->getDeclName());
- bool PropertyInPrimaryClass = false;
- for (; Found.first != Found.second; ++Found.first)
- if (isa<ObjCPropertyDecl>(*Found.first)) {
- PropertyInPrimaryClass = true;
- break;
- }
- if (!PropertyInPrimaryClass) {
+ DeclContext *DC = cast<DeclContext>(CCPrimary);
+ if (!ObjCPropertyDecl::findPropertyDecl(DC,
+ PIDecl->getDeclName().getAsIdentifierInfo())) {
// Protocol is not in the primary class. Must build one for it.
ObjCDeclSpec ProtocolPropertyODS;
// FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index f73ec9cb61c5..410bf9a7c1e9 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1525,28 +1525,30 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
for (llvm::tie(Con, ConEnd)
= ToRecordDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+
// Find the constructor (which may be a template).
CXXConstructorDecl *Constructor = 0;
FunctionTemplateDecl *ConstructorTmpl
- = dyn_cast<FunctionTemplateDecl>(*Con);
+ = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
Constructor
= cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
else
- Constructor = cast<CXXConstructorDecl>(*Con);
+ Constructor = cast<CXXConstructorDecl>(D);
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- AddTemplateOverloadCandidate(ConstructorTmpl,
- ConstructorTmpl->getAccess(),
+ AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
&From, 1, CandidateSet,
SuppressUserConversions, ForceRValue);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
- AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ AddOverloadCandidate(Constructor, FoundDecl,
&From, 1, CandidateSet,
SuppressUserConversions, ForceRValue);
}
@@ -1569,7 +1571,8 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
= FromRecordDecl->getVisibleConversionFunctions();
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
- NamedDecl *D = *I;
+ DeclAccessPair FoundDecl = I.getPair();
+ NamedDecl *D = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
@@ -1583,11 +1586,11 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, I.getAccess(),
+ AddTemplateConversionCandidate(ConvTemplate, FoundDecl,
ActingContext, From, ToType,
CandidateSet);
else
- AddConversionCandidate(Conv, I.getAccess(), ActingContext,
+ AddConversionCandidate(Conv, FoundDecl, ActingContext,
From, ToType, CandidateSet);
}
}
@@ -2383,7 +2386,7 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
/// code completion.
void
Sema::AddOverloadCandidate(FunctionDecl *Function,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
@@ -2404,7 +2407,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// function, e.g., X::f(). We use an empty type for the implied
// object argument (C++ [over.call.func]p3), and the acting context
// is irrelevant.
- AddMethodCandidate(Method, Access, Method->getParent(),
+ AddMethodCandidate(Method, FoundDecl, Method->getParent(),
QualType(), Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
return;
@@ -2434,8 +2437,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.FoundDecl = FoundDecl;
Candidate.Function = Function;
- Candidate.Access = Access;
Candidate.Viable = true;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
@@ -2500,28 +2503,28 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
- // FIXME: using declarations
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) {
+ NamedDecl *D = F.getDecl()->getUnderlyingDecl();
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
- AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getAccess(),
+ AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
cast<CXXMethodDecl>(FD)->getParent(),
Args[0]->getType(), Args + 1, NumArgs - 1,
CandidateSet, SuppressUserConversions);
else
- AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(FD, F.getPair(), Args, NumArgs, CandidateSet,
SuppressUserConversions);
} else {
- FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*F);
+ FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(D);
if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
!cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
- AddMethodTemplateCandidate(FunTmpl, F.getAccess(),
+ AddMethodTemplateCandidate(FunTmpl, F.getPair(),
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
/*FIXME: explicit args */ 0,
Args[0]->getType(), Args + 1, NumArgs - 1,
CandidateSet,
SuppressUserConversions);
else
- AddTemplateOverloadCandidate(FunTmpl, AS_none,
+ AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
/*FIXME: explicit args */ 0,
Args, NumArgs, CandidateSet,
SuppressUserConversions);
@@ -2531,12 +2534,12 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
/// AddMethodCandidate - Adds a named decl (which is some kind of
/// method) as a method candidate to the given overload set.
-void Sema::AddMethodCandidate(NamedDecl *Decl,
- AccessSpecifier Access,
+void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions, bool ForceRValue) {
+ NamedDecl *Decl = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());
if (isa<UsingShadowDecl>(Decl))
@@ -2545,13 +2548,14 @@ void Sema::AddMethodCandidate(NamedDecl *Decl,
if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) {
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
"Expected a member function template");
- AddMethodTemplateCandidate(TD, Access, ActingContext, /*ExplicitArgs*/ 0,
+ AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
+ /*ExplicitArgs*/ 0,
ObjectType, Args, NumArgs,
CandidateSet,
SuppressUserConversions,
ForceRValue);
} else {
- AddMethodCandidate(cast<CXXMethodDecl>(Decl), Access, ActingContext,
+ AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, Args, NumArgs,
CandidateSet, SuppressUserConversions, ForceRValue);
}
@@ -2567,7 +2571,7 @@ void Sema::AddMethodCandidate(NamedDecl *Decl,
/// a slightly hacky way to implement the overloading rules for elidable copy
/// initialization in C++0x (C++0x 12.8p15).
void
-Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access,
+Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -2587,8 +2591,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access,
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.FoundDecl = FoundDecl;
Candidate.Function = Method;
- Candidate.Access = Access;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
@@ -2666,7 +2670,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access,
/// function template specialization.
void
Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
@@ -2702,7 +2706,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
assert(Specialization && "Missing member function template specialization?");
assert(isa<CXXMethodDecl>(Specialization) &&
"Specialization is not a member function?");
- AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Access,
+ AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, Args, NumArgs,
CandidateSet, SuppressUserConversions, ForceRValue);
}
@@ -2712,7 +2716,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
/// an appropriate function template specialization.
void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -2737,8 +2741,8 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
Args, NumArgs, Specialization, Info)) {
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate &Candidate = CandidateSet.back();
+ Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
- Candidate.Access = Access;
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
@@ -2753,7 +2757,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// Add the function template specialization produced by template argument
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
- AddOverloadCandidate(Specialization, Access, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(Specialization, FoundDecl, Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
}
@@ -2765,7 +2769,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
/// conversion function produces).
void
Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet) {
@@ -2781,8 +2785,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.FoundDecl = FoundDecl;
Candidate.Function = Conversion;
- Candidate.Access = Access;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
@@ -2869,7 +2873,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
/// [temp.deduct.conv]).
void
Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
CXXRecordDecl *ActingDC,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet) {
@@ -2893,7 +2897,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
// Add the conversion function template specialization produced by
// template argument deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
- AddConversionCandidate(Specialization, Access, ActingDC, From, ToType,
+ AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
CandidateSet);
}
@@ -2903,7 +2907,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
/// with the given arguments (C++ [over.call.object]p2-4). Proto is
/// the type of function that we'll eventually be calling.
void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
QualType ObjectType,
@@ -2917,8 +2921,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.FoundDecl = FoundDecl;
Candidate.Function = 0;
- Candidate.Access = Access;
Candidate.Surrogate = Conversion;
Candidate.Viable = true;
Candidate.IsSurrogate = true;
@@ -3066,7 +3070,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
OperEnd = Operators.end();
Oper != OperEnd;
++Oper)
- AddMethodCandidate(*Oper, Oper.getAccess(), Args[0]->getType(),
+ AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
Args + 1, NumArgs - 1, CandidateSet,
/* SuppressUserConversions = */ false);
}
@@ -3091,8 +3095,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.FoundDecl = DeclAccessPair::make(0, AS_none);
Candidate.Function = 0;
- Candidate.Access = AS_none;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.BuiltinTypes.ResultTy = ResultTy;
@@ -4179,15 +4183,16 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
// For each of the ADL candidates we found, add it to the overload
// set.
for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
+ DeclAccessPair FoundDecl = DeclAccessPair::make(*I, AS_none);
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
if (ExplicitTemplateArgs)
continue;
- AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet,
false, false, PartialOverloading);
} else
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I),
- AS_none, ExplicitTemplateArgs,
+ FoundDecl, ExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
}
}
@@ -4951,12 +4956,11 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
}
}
-static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, NamedDecl *D,
- AccessSpecifier AS) {
+static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) {
if (isa<UnresolvedLookupExpr>(E))
- return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D, AS);
+ return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D);
- return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D, AS);
+ return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D);
}
/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
@@ -5013,7 +5017,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
- UnresolvedSet<4> Matches; // contains only FunctionDecls
+ llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
bool FoundNonTemplateFunction = false;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
E = OvlExpr->decls_end(); I != E; ++I) {
@@ -5057,8 +5061,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// a candidate? Find a testcase before changing the code.
assert(FunctionType
== Context.getCanonicalType(Specialization->getType()));
- Matches.addDecl(cast<FunctionDecl>(Specialization->getCanonicalDecl()),
- I.getAccess());
+ Matches.push_back(std::make_pair(I.getPair(),
+ cast<FunctionDecl>(Specialization->getCanonicalDecl())));
}
continue;
@@ -5081,8 +5085,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) ||
IsNoReturnConversion(Context, FunDecl->getType(), FunctionType,
ResultTy)) {
- Matches.addDecl(cast<FunctionDecl>(FunDecl->getCanonicalDecl()),
- I.getAccess());
+ Matches.push_back(std::make_pair(I.getPair(),
+ cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
FoundNonTemplateFunction = true;
}
}
@@ -5092,10 +5096,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
if (Matches.empty())
return 0;
else if (Matches.size() == 1) {
- FunctionDecl *Result = cast<FunctionDecl>(*Matches.begin());
+ FunctionDecl *Result = Matches[0].second;
MarkDeclarationReferenced(From->getLocStart(), Result);
if (Complain)
- CheckUnresolvedAccess(*this, OvlExpr, Result, Matches.begin().getAccess());
+ CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
return Result;
}
@@ -5112,50 +5116,54 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// two-pass algorithm (similar to the one used to identify the
// best viable function in an overload set) that identifies the
// best function template (if it exists).
+
+ UnresolvedSet<4> MatchesCopy; // TODO: avoid!
+ for (unsigned I = 0, E = Matches.size(); I != E; ++I)
+ MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess());
UnresolvedSetIterator Result =
- getMostSpecialized(Matches.begin(), Matches.end(),
+ getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(),
TPOC_Other, From->getLocStart(),
PDiag(),
PDiag(diag::err_addr_ovl_ambiguous)
- << Matches[0]->getDeclName(),
+ << Matches[0].second->getDeclName(),
PDiag(diag::note_ovl_candidate)
<< (unsigned) oc_function_template);
- assert(Result != Matches.end() && "no most-specialized template");
+ assert(Result != MatchesCopy.end() && "no most-specialized template");
MarkDeclarationReferenced(From->getLocStart(), *Result);
- if (Complain)
- CheckUnresolvedAccess(*this, OvlExpr, *Result, Result.getAccess());
+ if (Complain) {
+ DeclAccessPair FoundDecl = Matches[Result - MatchesCopy.begin()].first;
+ CheckUnresolvedAccess(*this, OvlExpr, FoundDecl);
+ }
return cast<FunctionDecl>(*Result);
}
// [...] any function template specializations in the set are
// eliminated if the set also contains a non-template function, [...]
for (unsigned I = 0, N = Matches.size(); I != N; ) {
- if (cast<FunctionDecl>(Matches[I].getDecl())->getPrimaryTemplate() == 0)
+ if (Matches[I].second->getPrimaryTemplate() == 0)
++I;
else {
- Matches.erase(I);
- --N;
+ Matches[I] = Matches[--N];
+ Matches.set_size(N);
}
}
// [...] After such eliminations, if any, there shall remain exactly one
// selected function.
if (Matches.size() == 1) {
- UnresolvedSetIterator Match = Matches.begin();
- MarkDeclarationReferenced(From->getLocStart(), *Match);
+ MarkDeclarationReferenced(From->getLocStart(), Matches[0].second);
if (Complain)
- CheckUnresolvedAccess(*this, OvlExpr, *Match, Match.getAccess());
- return cast<FunctionDecl>(*Match);
+ CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
+ return cast<FunctionDecl>(Matches[0].second);
}
// FIXME: We should probably return the same thing that BestViableFunction
// returns (even if we issue the diagnostics here).
Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
- << Matches[0]->getDeclName();
- for (UnresolvedSetIterator I = Matches.begin(),
- E = Matches.end(); I != E; ++I)
- NoteOverloadCandidate(cast<FunctionDecl>(*I));
+ << Matches[0].second->getDeclName();
+ for (unsigned I = 0, E = Matches.size(); I != E; ++I)
+ NoteOverloadCandidate(Matches[I].second);
return 0;
}
@@ -5227,25 +5235,26 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
/// \brief Add a single candidate to the overload set.
static void AddOverloadedCallCandidate(Sema &S,
- NamedDecl *Callee,
- AccessSpecifier Access,
+ DeclAccessPair FoundDecl,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading) {
+ NamedDecl *Callee = FoundDecl.getDecl();
if (isa<UsingShadowDecl>(Callee))
Callee = cast<UsingShadowDecl>(Callee)->getTargetDecl();
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
assert(!ExplicitTemplateArgs && "Explicit template arguments?");
- S.AddOverloadCandidate(Func, Access, Args, NumArgs, CandidateSet,
+ S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet,
false, false, PartialOverloading);
return;
}
if (FunctionTemplateDecl *FuncTemplate
= dyn_cast<FunctionTemplateDecl>(Callee)) {
- S.AddTemplateOverloadCandidate(FuncTemplate, Access, ExplicitTemplateArgs,
+ S.AddTemplateOverloadCandidate(FuncTemplate, FoundDecl,
+ ExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
return;
}
@@ -5301,7 +5310,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
E = ULE->decls_end(); I != E; ++I)
- AddOverloadedCallCandidate(*this, *I, I.getAccess(), ExplicitTemplateArgs,
+ AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs,
Args, NumArgs, CandidateSet,
PartialOverloading);
@@ -5423,7 +5432,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
- CheckUnresolvedLookupAccess(ULE, FDecl, Best->getAccess());
+ CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
Fn = FixOverloadedFunctionReference(Fn, FDecl);
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc);
}
@@ -5549,7 +5558,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
- CheckMemberOperatorAccess(OpLoc, Args[0], 0, Method, Best->getAccess());
+ CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl);
if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method))
return ExprError();
@@ -5733,8 +5742,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
// Best->Access is only meaningful for class members.
- CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Method,
- Best->getAccess());
+ CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Best->FoundDecl);
OwningExprResult Arg1
= PerformCopyInitialization(
@@ -5908,8 +5916,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- CheckMemberOperatorAccess(LLoc, Args[0], Args[1], FnDecl,
- Best->getAccess());
+ CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
@@ -6054,12 +6061,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
if (TemplateArgs)
continue;
- AddMethodCandidate(Method, I.getAccess(), ActingDC, ObjectType,
+ AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType,
Args, NumArgs,
CandidateSet, /*SuppressUserConversions=*/false);
} else {
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
- I.getAccess(), ActingDC, TemplateArgs,
+ I.getPair(), ActingDC, TemplateArgs,
ObjectType, Args, NumArgs,
CandidateSet,
/*SuppressUsedConversions=*/false);
@@ -6072,7 +6079,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
- CheckUnresolvedMemberAccess(UnresExpr, Method, Best->getAccess());
+ CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
break;
case OR_No_Viable_Function:
@@ -6176,7 +6183,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
- AddMethodCandidate(*Oper, Oper.getAccess(), Object->getType(),
+ AddMethodCandidate(Oper.getPair(), Object->getType(),
Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/ false);
}
@@ -6221,7 +6228,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
ConvType = ConvPtrType->getPointeeType();
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
- AddSurrogateCandidate(Conv, I.getAccess(), ActingContext, Proto,
+ AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto,
Object->getType(), Args, NumArgs,
CandidateSet);
}
@@ -6278,7 +6285,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
= cast<CXXConversionDecl>(
Best->Conversions[0].UserDefined.ConversionFunction);
- CheckMemberOperatorAccess(LParenLoc, Object, 0, Conv, Best->getAccess());
+ CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
@@ -6293,8 +6300,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
CommaLocs, RParenLoc).release();
}
- CheckMemberOperatorAccess(LParenLoc, Object, 0,
- Best->Function, Best->getAccess());
+ CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
// We found an overloaded operator(). Build a CXXOperatorCallExpr
// that calls this method, using Object for the implicit object
@@ -6429,13 +6435,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
- NamedDecl *D = *Oper;
- CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
-
- AddMethodCandidate(cast<CXXMethodDecl>(D), Oper.getAccess(), ActingContext,
- Base->getType(), 0, 0, CandidateSet,
+ AddMethodCandidate(Oper.getPair(), Base->getType(), 0, 0, CandidateSet,
/*SuppressUserConversions=*/false);
}
@@ -6470,6 +6470,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
return ExprError();
}
+ CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
+
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, Method))
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 58e416c87e59..cff4774fba27 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -18,6 +18,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
+#include "clang/AST/UnresolvedSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -450,6 +451,11 @@ namespace clang {
/// function pointer or reference (C++ [over.call.object]).
FunctionDecl *Function;
+ /// FoundDecl - The original declaration that was looked up /
+ /// invented / otherwise found, together with its access.
+ /// Might be a UsingShadowDecl or a FunctionTemplateDecl.
+ DeclAccessPair FoundDecl;
+
// BuiltinTypes - Provides the return and parameter types of a
// built-in overload candidate. Only valid when Function is NULL.
struct {
@@ -486,14 +492,6 @@ namespace clang {
/// Actually an OverloadFailureKind.
unsigned char FailureKind;
- /// PathAccess - The 'path access' to the given function/conversion.
- /// Actually an AccessSpecifier.
- unsigned Access;
-
- AccessSpecifier getAccess() const {
- return AccessSpecifier(Access);
- }
-
/// A structure used to record information about a failed
/// template argument deduction.
struct DeductionFailureInfo {
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index 9a266c937939..209ca6531cc2 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -1,18 +1,18 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
void f1() {
- int k, y;
+ int k, y; // expected-warning{{unused variable 'k'}} expected-warning{{unused variable 'y'}}
int abc=1;
- long idx=abc+3*5; // expected-warning {{never read}}
+ long idx=abc+3*5; // expected-warning {{never read}} expected-warning{{unused variable 'idx'}}
}
void f2(void *b) {
char *c = (char*)b; // no-warning
- char *d = b+1; // expected-warning {{never read}}
+ char *d = b+1; // expected-warning {{never read}} expected-warning{{unused variable 'd'}}
printf("%s", c); // expected-warning{{implicitly declaring C library function 'printf' with type 'int (char const *, ...)'}} \
// expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
}
@@ -40,7 +40,7 @@ void f4(int k) {
void f5() {
int x = 4; // no-warning
- int *p = &x; // expected-warning{{never read}}
+ int *p = &x; // expected-warning{{never read}} expected-warning{{unused variable 'p'}}
}
@@ -105,13 +105,20 @@ int f11b() {
}
int f12a(int y) {
- int x = y; // expected-warning{{never read}}
+ int x = y; // expected-warning{{unused variable 'x'}}
return 1;
}
int f12b(int y) {
int x __attribute__((unused)) = y; // no-warning
return 1;
}
+int f12c(int y) {
+ // Allow initialiation of scalar variables by parameters as a form of
+ // defensive programming.
+ int x = y; // no-warning
+ x = 1;
+ return x;
+}
// Filed with PR 2630. This code should produce no warnings.
int f13(void)
@@ -138,7 +145,7 @@ int f14(int count) {
// Test case for <rdar://problem/6248086>
void f15(unsigned x, unsigned y) {
int count = x * y; // no-warning
- int z[count];
+ int z[count]; // expected-warning{{unused variable 'z'}}
}
int f16(int x) {
@@ -367,7 +374,7 @@ void f23(int argc, char **argv) {
}
void f23_pos(int argc, char **argv) {
- int shouldLog = (argc > 1); // expected-warning{{Value stored to 'shouldLog' during its initialization is never read}}
+ int shouldLog = (argc > 1); // expected-warning{{Value stored to 'shouldLog' during its initialization is never read}} expected-warning{{unused variable 'shouldLog'}}
^{
f23_aux("I did too use it!\n");
}();
@@ -377,7 +384,7 @@ void f24_A(int y) {
// FIXME: One day this should be reported as dead since 'z = x + y' is dead.
int x = (y > 2); // no-warning
^ {
- int z = x + y; // expected-warning{{Value stored to 'z' during its initialization is never read}}
+ int z = x + y; // expected-warning{{Value stored to 'z' during its initialization is never read}} expected-warning{{unused variable 'z'}}
}();
}
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 21a54c34d78f..898a33efe124 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -888,3 +888,25 @@ char *rdar_7242010(int count, char **y) {
return y[0]; // no-warning
}
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7770737>
+//===----------------------------------------------------------------------===//
+
+struct rdar_7770737_s { intptr_t p; };
+void rdar_7770737_aux(struct rdar_7770737_s *p);
+int rdar_7770737(void)
+{
+ int x;
+
+ // Previously 'f' was not properly invalidated, causing the use of
+ // an uninitailized value below.
+ struct rdar_7770737_s f = { .p = (intptr_t)&x };
+ rdar_7770737_aux(&f);
+ return x; // no-warning
+}
+int rdar_7770737_pos(void)
+{
+ int x;
+ struct rdar_7770737_s f = { .p = (intptr_t)&x };
+ return x; // expected-warning{{Undefined or garbage value returned to caller}}
+}
diff --git a/test/Analysis/uninit-vals-ps-region.c b/test/Analysis/uninit-vals-ps-region.m
index 44f506efadb2..7e2fff9db530 100644
--- a/test/Analysis/uninit-vals-ps-region.c
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -45,3 +45,18 @@ void test_uninit_neg() {
test_unit_aux2(v2.x + v1.y); // no-warning
}
+extern void test_uninit_struct_arg_aux(struct TestUninit arg);
+void test_uninit_struct_arg() {
+ struct TestUninit x;
+ test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
+}
+
+@interface Foo
+- (void) passVal:(struct TestUninit)arg;
+@end
+void testFoo(Foo *o) {
+ struct TestUninit x;
+ [o passVal:x]; // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
+}
+
+
diff --git a/test/CXX/class.access/class.access.nest/p1.cpp b/test/CXX/class.access/class.access.nest/p1.cpp
new file mode 100644
index 000000000000..d2644c6ef476
--- /dev/null
+++ b/test/CXX/class.access/class.access.nest/p1.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+
+// Derived from GNU's std::string
+namespace test0 {
+ class A {
+ struct B {
+ unsigned long length;
+ };
+ struct C : B {
+ static const unsigned long max_length;
+ };
+ };
+
+ const unsigned long A::C::max_length = sizeof(B);
+}
+
+// Example from the standard.
+namespace test1 {
+ class E {
+ int x;
+ class B {};
+
+ class I {
+ B b;
+ int y; // expected-note {{declared private here}}
+ void f(E* p, int i) {
+ p->x = i;
+ }
+ };
+
+ int g(I* p) { return p->y; } // expected-error {{'y' is a private member of 'test1::E::I'}}
+ };
+}
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 83b4227aa3bc..851cd3d00884 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -115,3 +115,37 @@ namespace test0 {
}
};
}
+
+// Make sure that friends have access to inherited protected members.
+namespace test2 {
+ struct X;
+
+ class ilist_half_node {
+ friend struct ilist_walker_bad;
+ X *Prev;
+ protected:
+ X *getPrev() { return Prev; }
+ };
+
+ class ilist_node : private ilist_half_node { // expected-note {{declared private here}} expected-note {{constrained by private inheritance here}}
+ friend struct ilist_walker;
+ X *Next;
+ X *getNext() { return Next; } // expected-note {{declared private here}}
+ };
+
+ struct X : ilist_node {};
+
+ struct ilist_walker {
+ static X *getPrev(X *N) { return N->getPrev(); }
+ static X *getNext(X *N) { return N->getNext(); }
+ };
+
+ struct ilist_walker_bad {
+ static X *getPrev(X *N) { return N->getPrev(); } // \
+ // expected-error {{'getPrev' is a private member of 'test2::ilist_half_node'}} \
+ // expected-error {{cannot cast 'test2::X' to its private base class 'test2::ilist_half_node'}}
+
+ static X *getNext(X *N) { return N->getNext(); } // \
+ // expected-error {{'getNext' is a private member of 'test2::ilist_node'}}
+ };
+}
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 15b336a4d8e6..bc69bee657c9 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -112,9 +112,10 @@ namespace test3 {
A local; // expected-error {{variable of type 'test3::A' has private destructor}}
}
- template <unsigned N> class Base { ~Base(); }; // expected-note 8 {{declared private here}}
- class Base2 : virtual Base<2> { ~Base2(); }; // expected-note 2 {{declared private here}}
- class Base3 : virtual Base<3> { public: ~Base3(); };
+ template <unsigned N> class Base { ~Base(); }; // expected-note 14 {{declared private here}}
+ class Base2 : virtual Base<2> { ~Base2(); }; // expected-note 3 {{declared private here}} \
+ // expected-error {{base class 'Base<2>' has private destructor}}
+ class Base3 : virtual Base<3> { public: ~Base3(); }; // expected-error {{base class 'Base<3>' has private destructor}}
// These don't cause diagnostics because we don't need the destructor.
class Derived0 : Base<0> { ~Derived0(); };
@@ -130,11 +131,11 @@ namespace test3 {
~Derived2() {}
};
- class Derived3 : // expected-error {{inherited virtual base class 'Base<2>' has private destructor}} \
- // expected-error {{inherited virtual base class 'Base<3>' has private destructor}}
- Base<0>, // expected-error {{base class 'Base<0>' has private destructor}}
- virtual Base<1>, // expected-error {{base class 'Base<1>' has private destructor}}
- Base2, // expected-error {{base class 'test3::Base2' has private destructor}}
+ class Derived3 : // expected-error 2 {{inherited virtual base class 'Base<2>' has private destructor}} \
+ // expected-error 2 {{inherited virtual base class 'Base<3>' has private destructor}}
+ Base<0>, // expected-error 2 {{base class 'Base<0>' has private destructor}}
+ virtual Base<1>, // expected-error 2 {{base class 'Base<1>' has private destructor}}
+ Base2, // expected-error 2 {{base class 'test3::Base2' has private destructor}}
virtual Base3
{};
Derived3 d3;
@@ -220,3 +221,44 @@ namespace test6 {
Test2 a = t;
}
}
+
+// Redeclaration lookups are not accesses.
+namespace test7 {
+ class A {
+ int private_member;
+ };
+ class B : A {
+ int foo(int private_member) {
+ return 0;
+ }
+ };
+}
+
+// Ignored operator new and delete overloads are not
+namespace test8 {
+ typedef __typeof__(sizeof(int)) size_t;
+
+ class A {
+ void *operator new(size_t s);
+ void operator delete(void *p);
+ public:
+ void *operator new(size_t s, int n);
+ void operator delete(void *p, int n);
+ };
+
+ void test() {
+ new (2) A();
+ }
+}
+
+// Don't silently upgrade forbidden-access paths to private.
+namespace test9 {
+ class A {
+ public: static int x;
+ };
+ class B : private A { // expected-note {{constrained by private inheritance here}}
+ };
+ class C : public B {
+ static int getX() { return x; } // expected-error {{'x' is a private member of 'test9::A'}}
+ };
+}
diff --git a/test/CXX/class/class.union/p1.cpp b/test/CXX/class/class.union/p1.cpp
index f53783eb5f3a..e974d825d6ef 100644
--- a/test/CXX/class/class.union/p1.cpp
+++ b/test/CXX/class/class.union/p1.cpp
@@ -46,25 +46,25 @@ union U1 {
union U2 {
struct {
- Virtual v; // expected-note {{because type 'U2::<anonymous>' has a member with a non-trivial copy constructor}}
+ Virtual v; // expected-note {{because type 'U2::<anonymous struct}}
} m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
struct {
- VirtualBase vbase; // expected-note {{because type 'U2::<anonymous>' has a member with a non-trivial copy constructor}}
+ VirtualBase vbase; // expected-note {{because type 'U2::<anonymous struct}}
} m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
struct {
- Ctor ctor; // expected-note {{because type 'U2::<anonymous>' has a member with a non-trivial constructor}}
+ Ctor ctor; // expected-note {{because type 'U2::<anonymous struct}}
} m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
struct {
- Ctor2 ctor2; // expected-note {{because type 'U2::<anonymous>' has a member with a non-trivial constructor}}
+ Ctor2 ctor2; // expected-note {{because type 'U2::<anonymous struct}}
} m3a; // expected-error {{union member 'm3a' has a non-trivial constructor}}
struct {
- CopyCtor copyctor; // expected-note {{because type 'U2::<anonymous>' has a member with a non-trivial copy constructor}}
+ CopyCtor copyctor; // expected-note {{because type 'U2::<anonymous struct}}
} m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
struct {
- CopyAssign copyassign; // expected-note {{because type 'U2::<anonymous>' has a member with a non-trivial copy assignment operator}}
+ CopyAssign copyassign; // expected-note {{because type 'U2::<anonymous struct}}
} m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
struct {
- Dtor dtor; // expected-note {{because type 'U2::<anonymous>' has a member with a non-trivial destructor}}
+ Dtor dtor; // expected-note {{because type 'U2::<anonymous struct}}
} m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
struct {
Okay okay;
diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
index 7a28e70c9ae6..f1b3c814c426 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm-only %s
+// RUN: %clang_cc1 -faccess-control -verify -emit-llvm-only %s
template <typename T> struct Num {
T value_;
@@ -54,3 +54,34 @@ int calc2() {
Num<int> result = x * n;
return result.get();
}
+
+// Reduced from GNU <locale>
+namespace test1 {
+ class A {
+ bool b; // expected-note {{declared private here}}
+ template <typename T> friend bool has(const A&);
+ };
+ template <typename T> bool has(const A &x) {
+ return x.b;
+ }
+ template <typename T> bool hasnot(const A &x) {
+ return x.b; // expected-error {{'b' is a private member of 'test1::A'}}
+ }
+}
+
+namespace test2 {
+ class A {
+ bool b; // expected-note {{declared private here}}
+ template <typename T> friend class HasChecker;
+ };
+ template <typename T> class HasChecker {
+ bool check(A *a) {
+ return a->b;
+ }
+ };
+ template <typename T> class HasNotChecker {
+ bool check(A *a) {
+ return a->b; // expected-error {{'b' is a private member of 'test2::A'}}
+ }
+ };
+}
diff --git a/test/CodeGen/atomic.c b/test/CodeGen/atomic.c
index ff304f57f01d..c201a1ad6606 100644
--- a/test/CodeGen/atomic.c
+++ b/test/CodeGen/atomic.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 > %t1
+// RUN: grep @llvm.memory.barrier %t1 | count 42
// RUN: grep @llvm.atomic.load.add.i32 %t1 | count 3
// RUN: grep @llvm.atomic.load.sub.i8 %t1 | count 2
// RUN: grep @llvm.atomic.load.min.i32 %t1
diff --git a/test/CodeGen/const-arithmetic.c b/test/CodeGen/const-arithmetic.c
new file mode 100644
index 000000000000..e12b4f6d92c1
--- /dev/null
+++ b/test/CodeGen/const-arithmetic.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @g1 = global [2 x i8*] [i8* getelementptr (i8* getelementptr inbounds ([0 x %struct.anon]* @g0, i32 0, i32 0, i32 0), i64 -2), i8* getelementptr (i8* getelementptr inbounds ([0 x %struct.anon]* @g0, i32 0, i32 0, i32 0), i64 -46)], align 8 ; <[2 x i8*]*> [#uses=0]
+// CHECK: @g2 = global [2 x i8*] [i8* getelementptr (i8* getelementptr inbounds ([0 x %struct.anon]* @g0, i32 0, i32 0, i32 0), i64 -2), i8* getelementptr (i8* getelementptr inbounds ([0 x %struct.anon]* @g0, i32 0, i32 0, i32 0), i64 -46)], align 8 ; <[2 x i8*]*> [#uses=0]
+
+extern struct { unsigned char a, b; } g0[];
+void *g1[] = {g0 + -1, g0 + -23 };
+void *g2[] = {g0 - 1, g0 - 23 };
diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp
index 4c781c62b29f..d689a4fdf493 100644
--- a/test/CodeGenCXX/attr.cpp
+++ b/test/CodeGenCXX/attr.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// CHECK: @test2 = alias i32 ()* @_Z5test1v
+
// CHECK: define i32 @_Z3foov() nounwind align 1024
int foo() __attribute__((aligned(1024)));
int foo() { }
@@ -18,3 +20,9 @@ void C::bar2() { }
// CHECK: define void @_ZN1C4bar3Ev(%class.C* %this) nounwind align 1024
void C::bar3() { }
+
+// PR6635
+// CHECK: define i32 @_Z5test1v()
+int test1() { return 10; }
+// CHECK at top of file
+extern "C" int test2() __attribute__((alias("_Z5test1v")));
diff --git a/test/CodeGenCXX/cxx-apple-kext.cpp b/test/CodeGenCXX/cxx-apple-kext.cpp
new file mode 100644
index 000000000000..8d67b53657af
--- /dev/null
+++ b/test/CodeGenCXX/cxx-apple-kext.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 %s -flto -S -o - |\
+// RUN: FileCheck --check-prefix=CHECK-NO-KEXT %s
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 %s -fapple-kext -flto -S -o - |\
+// RUN: FileCheck --check-prefix=CHECK-KEXT %s
+
+// CHECK-NO-KEXT: @_ZTI3foo = {{.*}} @_ZTVN10__cxxabiv117
+// CHECK-NO-KEXT-NOT: _GLOBAL__D_a
+// CHECK-NO-KEXT: @is_hosted = global
+// CHECK-NO-KEXT: call i32 @__cxa_atexit({{.*}} @_ZN3fooD1Ev
+// CHECK-NO-KEXT: declare i32 @__cxa_atexit
+
+// CHECK-KEXT: @_ZTV3foo =
+// CHECK-KEXT-NOT: @_ZTVN10__cxxabiv117
+// CHECK-KEXT-NOT: call i32 @__cxa_atexit({{.*}} @_ZN3fooD1Ev
+// CHECK-KEXT-NOT: declare i32 @__cxa_atexit
+// CHECK-KEXT: @is_freestanding = global
+// CHECK-KEXT: _GLOBAL__D_a
+// CHECK-KEXT: call void @_ZN3fooD1Ev(%class.foo* @a)
+
+class foo {
+public:
+ foo();
+ virtual ~foo();
+};
+
+foo a;
+foo::~foo() {}
+
+#if !(__STDC_HOSTED__ == 1)
+int is_freestanding = 1;
+#else
+int is_hosted = 1;
+#endif
+
+extern "C" void f1() {
+}
diff --git a/test/CodeGenCXX/deferred-global-init.cpp b/test/CodeGenCXX/deferred-global-init.cpp
index 802042dd8b90..24c8c675b006 100644
--- a/test/CodeGenCXX/deferred-global-init.cpp
+++ b/test/CodeGenCXX/deferred-global-init.cpp
@@ -11,6 +11,6 @@ void* bar() { return a; }
// CHECK: load i8** @foo
// CHECK: ret void
-// CHECK: define internal void @__cxx_global_initialization
+// CHECK: define internal void @_GLOBAL__I_a
// CHECK: call void @__cxx_global_var_init()
// CHECK: ret void
diff --git a/test/CodeGenCXX/global-dtor-no-atexit.cpp b/test/CodeGenCXX/global-dtor-no-atexit.cpp
new file mode 100644
index 000000000000..81e219989800
--- /dev/null
+++ b/test/CodeGenCXX/global-dtor-no-atexit.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64 %s -fno-use-cxa-atexit -emit-llvm -o - | FileCheck %s
+
+// CHECK: define internal void @_GLOBAL__D_a()
+// CHECK: call void @_ZN1AD1Ev(%class.A* @b)
+// CHECK: call void @_ZN1AD1Ev(%class.A* @a)
+// CHECK: }
+
+class A {
+public:
+ A();
+ ~A();
+};
+
+A a, b;
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
index b60e056d708f..7cbd55940b43 100644
--- a/test/CodeGenCXX/global-init.cpp
+++ b/test/CodeGenCXX/global-init.cpp
@@ -28,4 +28,4 @@ C c;
// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @d, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
D d;
-// CHECK: define internal void @__cxx_global_initialization() {
+// CHECK: define internal void @_GLOBAL__I_a() {
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 8dee41beb482..ec9c08c0ccaa 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -453,3 +453,18 @@ namespace test8 {
class B { static int value; };
template class A<B::value>;
}
+// CHECK: declare void @_ZN5test91fIiNS_3barEEEvRKNT0_3baz1XE
+namespace test9 {
+ template<class T>
+ struct foo {
+ typedef T X;
+ };
+ struct bar {
+ typedef foo<int> baz;
+ };
+ template <class zaz, class zed>
+ void f(const typename zed::baz::X&);
+ void g() {
+ f<int, bar>( 0);
+ }
+}
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index f11ae345cc7b..bc3d54b8e4a7 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -887,8 +887,8 @@ class E : virtual C { };
// CHECK-NEXT: -- (Test21::E, 8) vtable address --
// CHECK-NEXT: 15 | [unused] void Test21::F::f()
//
-// CHECK: Virtual base offset offsets for 'Test21::F'.
-// CHECK-NEXT: Test21::A | -32
+// CHECK: Virtual base offset offsets for 'Test21::F' (5 entries).
+// CHECK-NEXT: Test21::A | -32
// CHECK-NEXT: Test21::B | -40
// CHECK-NEXT: Test21::C | -48
// CHECK-NEXT: Test21::D | -56
diff --git a/test/Driver/cc-print-options.c b/test/Driver/cc-print-options.c
new file mode 100644
index 000000000000..7b798cb08a85
--- /dev/null
+++ b/test/Driver/cc-print-options.c
@@ -0,0 +1,7 @@
+// RUN: env CC_PRINT_OPTIONS=1 \
+// RUN: CC_PRINT_OPTIONS_FILE=%t.log \
+// RUN: %clang -S -o %t.s %s
+// RUN: FileCheck %s < %t.log
+
+// CHECK: [Logging clang options]{{.*}}clang{{.*}}"-S"
+
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index d34d566d1878..9ae81f178787 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -32,8 +32,8 @@
//
// Note that at conception, this exactly matches gcc.
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -miphoneos-version-min=2.0 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO 2> %t.log
-// RUN: grep '".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-iphoneos_version_min" "2.0" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-L" "ARG2" "-lgomp" "-L/usr/lib/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1/../../../i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1/../../.." "-filelist" "FOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-F" "ARG1"' %t.log
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -miphoneos-version-min=2.0 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO -l FOO 2> %t.log
+// RUN: grep '".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-iphoneos_version_min" "2.0" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-L" "ARG2" "-lgomp" "-L/usr/lib/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1/../../../i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1/../../.." "-filelist" "FOO" "-lFOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-F" "ARG1"' %t.log
// Don't run dsymutil on a fat build of an executable.
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch i386 -arch x86_64 -g %s 2> %t.log
diff --git a/test/Index/annotate-tokens-pp.c b/test/Index/annotate-tokens-pp.c
new file mode 100644
index 000000000000..485786e1c4e8
--- /dev/null
+++ b/test/Index/annotate-tokens-pp.c
@@ -0,0 +1,58 @@
+#define NOTHING(X,Y)
+#define STILL_NOTHING NOTHING(honk,warble)
+#define BAR baz
+#define WIBBLE(X, Y) X##Y
+NOTHING(more,junk) float WIBBLE(int, float);
+int BAR STILL_NOTHING;
+#include "foo.h"
+#undef BAR
+
+// RUN: c-index-test -test-annotate-tokens=%s:2:1:9:1 -I%S/Inputs %s | FileCheck %s
+// CHECK: Punctuation: "#" [2:1 - 2:2] preprocessing directive=
+// CHECK: Identifier: "define" [2:2 - 2:8] preprocessing directive=
+// CHECK: Identifier: "STILL_NOTHING" [2:9 - 2:22] macro definition=STILL_NOTHING
+// CHECK: Identifier: "NOTHING" [2:23 - 2:30] preprocessing directive=
+// CHECK: Punctuation: "(" [2:30 - 2:31] preprocessing directive=
+// CHECK: Identifier: "honk" [2:31 - 2:35] preprocessing directive=
+// CHECK: Punctuation: "," [2:35 - 2:36] preprocessing directive=
+// CHECK: Identifier: "warble" [2:36 - 2:42] preprocessing directive=
+// CHECK: Punctuation: ")" [2:42 - 2:43] preprocessing directive=
+// CHECK: Punctuation: "#" [3:1 - 3:2] preprocessing directive=
+// CHECK: Identifier: "define" [3:2 - 3:8] preprocessing directive=
+// CHECK: Identifier: "BAR" [3:9 - 3:12] macro definition=BAR
+// CHECK: Identifier: "baz" [3:13 - 3:16] preprocessing directive=
+// CHECK: Punctuation: "#" [4:1 - 4:2] preprocessing directive=
+// CHECK: Identifier: "define" [4:2 - 4:8] preprocessing directive=
+// CHECK: Identifier: "WIBBLE" [4:9 - 4:15] macro definition=WIBBLE
+// CHECK: Punctuation: "(" [4:15 - 4:16] preprocessing directive=
+// CHECK: Identifier: "X" [4:16 - 4:17] preprocessing directive=
+// CHECK: Punctuation: "," [4:17 - 4:18] preprocessing directive=
+// CHECK: Identifier: "Y" [4:19 - 4:20] preprocessing directive=
+// CHECK: Punctuation: ")" [4:20 - 4:21] preprocessing directive=
+// CHECK: Identifier: "X" [4:22 - 4:23] preprocessing directive=
+// CHECK: Punctuation: "##" [4:23 - 4:25] preprocessing directive=
+// CHECK: Identifier: "Y" [4:25 - 4:26] preprocessing directive=
+// CHECK: Identifier: "NOTHING" [5:1 - 5:8] macro instantiation=NOTHING:1:9
+// CHECK: Punctuation: "(" [5:8 - 5:9]
+// CHECK: Identifier: "more" [5:9 - 5:13]
+// CHECK: Punctuation: "," [5:13 - 5:14]
+// CHECK: Identifier: "junk" [5:14 - 5:18]
+// CHECK: Punctuation: ")" [5:18 - 5:19]
+// CHECK: Keyword: "float" [5:20 - 5:25]
+// CHECK: Identifier: "WIBBLE" [5:26 - 5:32] macro instantiation=WIBBLE:4:9
+// CHECK: Punctuation: "(" [5:32 - 5:33]
+// CHECK: Keyword: "int" [5:33 - 5:36]
+// CHECK: Punctuation: "," [5:36 - 5:37]
+// CHECK: Keyword: "float" [5:38 - 5:43]
+// CHECK: Punctuation: ")" [5:43 - 5:44]
+// CHECK: Punctuation: ";" [5:44 - 5:45]
+// CHECK: Keyword: "int" [6:1 - 6:4]
+// CHECK: Identifier: "BAR" [6:5 - 6:8] macro instantiation=BAR:3:9
+// CHECK: Identifier: "STILL_NOTHING" [6:9 - 6:22] macro instantiation=STILL_NOTHING:2:9
+// CHECK: Punctuation: ";" [6:22 - 6:23]
+// CHECK: Punctuation: "#" [7:1 - 7:2] preprocessing directive=
+// CHECK: Identifier: "include" [7:2 - 7:9] preprocessing directive=
+// CHECK: Literal: ""foo.h"" [7:10 - 7:17] preprocessing directive=
+// CHECK: Punctuation: "#" [8:1 - 8:2] preprocessing directive=
+// CHECK: Identifier: "undef" [8:2 - 8:7] preprocessing directive=
+// CHECK: Identifier: "BAR" [8:8 - 8:11] preprocessing directive=
diff --git a/test/Index/c-index-getCursor-pp.c b/test/Index/c-index-getCursor-pp.c
new file mode 100644
index 000000000000..67fcfef2e4be
--- /dev/null
+++ b/test/Index/c-index-getCursor-pp.c
@@ -0,0 +1,18 @@
+#define OBSCURE(X) X
+#define DECORATION
+
+typedef int T;
+void OBSCURE(func)(int x) {
+ OBSCURE(T) DECORATION value;
+}
+
+// RUN: c-index-test -cursor-at=%s:1:11 %s | FileCheck -check-prefix=CHECK-1 %s
+// CHECK-1: macro definition=OBSCURE
+// RUN: c-index-test -cursor-at=%s:2:14 %s | FileCheck -check-prefix=CHECK-2 %s
+// CHECK-2: macro definition=DECORATION
+// RUN: c-index-test -cursor-at=%s:5:7 %s | FileCheck -check-prefix=CHECK-3 %s
+// CHECK-3: macro instantiation=OBSCURE:1:9
+// RUN: c-index-test -cursor-at=%s:6:6 %s | FileCheck -check-prefix=CHECK-4 %s
+// CHECK-4: macro instantiation=OBSCURE:1:9
+// RUN: c-index-test -cursor-at=%s:6:19 %s | FileCheck -check-prefix=CHECK-5 %s
+// CHECK-5: macro instantiation=DECORATION:2:9
diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m
index 8341b80a673f..3cf1b6dcfa0d 100644
--- a/test/Index/c-index-getCursor-test.m
+++ b/test/Index/c-index-getCursor-test.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -detailed-preprocessing-record -o %t.ast
// RUN: c-index-test -test-file-scan %t.ast %s | FileCheck %s
@interface Foo
{
@@ -52,6 +52,13 @@ int main (int argc, const char * argv[]) {
main(someEnum, (const char **)bee);
}
+#define CONCAT(X, Y) X##Y
+
+void f() {
+ int CONCAT(my,_var);
+}
+#undef CONCAT
+
// CHECK: [1:1 - 3:1] Invalid Cursor => NoDeclFound
// CHECK: [3:1 - 7:1] ObjCInterfaceDecl=Foo:3:12
// CHECK: [7:1 - 7:7] ObjCInstanceMethodDecl=foo:7:1
@@ -155,3 +162,7 @@ int main (int argc, const char * argv[]) {
// CHECK: [52:33 - 52:36] DeclRefExpr=bee:45:8
// CHECK: [52:36 - 52:37] CallExpr=main:44:5
// CHECK: [52:37 - 53:2] UnexposedStmt=
+// CHECK: [55:9 - 55:26] macro definition=CONCAT
+// CHECK: [57:6 - 57:10] FunctionDecl=f:57:6 (Definition)
+// CHECK: [58:4 - 58:8] VarDecl=my_var:58:8 (Definition)
+// CHECK: [58:8 - 58:14] macro instantiation=CONCAT:55:9
diff --git a/test/PCH/changed-files.c b/test/PCH/changed-files.c
index 36453c48e716..dd08bddd75e7 100644
--- a/test/PCH/changed-files.c
+++ b/test/PCH/changed-files.c
@@ -1,11 +1,26 @@
const char *s0 = m0;
+int s1 = m1;
+const char *s2 = m0;
-// RUN: echo '#define m0 ""' > %t.h
-// RUN: %clang_cc1 -emit-pch -o %t.h.pch %t.h
-// RUN: echo '' > %t.h
-// RUN: not %clang_cc1 -include-pch %t.h.pch %s 2>&1 | grep "size of file"
+// FIXME: This test fails inexplicably on Windows in a manner that makes it
+// look like standard error isn't getting flushed properly.
-// RUN: echo '#define m0 000' > %t.h
-// RUN: %clang_cc1 -emit-pch -o %t.h.pch %t.h
-// RUN: echo '' > %t.h
-// RUN: not %clang_cc1 -include-pch %t.h.pch %s 2>&1 | grep "size of file"
+// RUN: true
+// RUNx: echo '#define m0 ""' > %t.h
+// RUNx: %clang_cc1 -emit-pch -o %t.h.pch %t.h
+// RUNx: echo '' > %t.h
+// RUNx: not %clang_cc1 -include-pch %t.h.pch %s 2> %t.stderr
+// RUNx: grep "modified" %t.stderr
+
+// RUNx: echo '#define m0 000' > %t.h
+// RUNx: %clang_cc1 -emit-pch -o %t.h.pch %t.h
+// RUNx: echo '' > %t.h
+// RUNx: not %clang_cc1 -include-pch %t.h.pch %s 2> %t.stderr
+// RUNx: grep "modified" %t.stderr
+
+// RUNx: echo '#define m0 000' > %t.h
+// RUNx: echo "#define m1 'abcd'" >> %t.h
+// RUNx: %clang_cc1 -emit-pch -o %t.h.pch %t.h
+// RUNx: echo '' > %t.h
+// RUNx: not %clang_cc1 -include-pch %t.h.pch %s 2> %t.stderr
+// RUNx: grep "modified" %t.stderr
diff --git a/test/PCH/headermap.h b/test/PCH/headermap.h
new file mode 100644
index 000000000000..efab2d8cab6e
--- /dev/null
+++ b/test/PCH/headermap.h
@@ -0,0 +1,3 @@
+/* Helper for the headermap.m test */
+int x = 17;
+
diff --git a/test/PCH/headermap.m b/test/PCH/headermap.m
new file mode 100644
index 000000000000..6ba83d7cf741
--- /dev/null
+++ b/test/PCH/headermap.m
@@ -0,0 +1,15 @@
+// RUN: touch %t.hmap
+
+// RUN: %clang_cc1 -x objective-c -emit-pch -o %t.h.pch %S/headermap.h
+// RUN: %clang_cc1 -include-pch %t.h.pch %s
+
+// RUN: %clang_cc1 -x objective-c -emit-pch -o %t.h.pch %S/headermap.h
+// RUN: %clang_cc1 -include-pch %t.h.pch -I%t.hmap %s
+
+// RUN: %clang_cc1 -x objective-c -I%t.hmap -emit-pch -o %t.h.pch %S/headermap.h
+// RUN: %clang_cc1 -include-pch %t.h.pch %s
+
+// RUN: %clang_cc1 -x objective-c -I%t.hmap -emit-pch -o %t.h.pch %S/headermap.h
+// RUN: %clang_cc1 -include-pch %t.h.pch -I%t.hmap %s
+#import "headermap.h"
+
diff --git a/test/Sema/block-byref-args.c b/test/Sema/block-byref-args.c
deleted file mode 100644
index 255c97b280c9..000000000000
--- a/test/Sema/block-byref-args.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks
-
-int printf(const char *, ...);
-
-int main(int argc, char **argv) {
- __block void(*bobTheFunction)(void);
- __block void(^bobTheBlock)(void);
-
- bobTheBlock = ^{;};
-
- __block int JJJJ;
- __attribute__((__blocks__(byref))) int III;
-
- int (^XXX)(void) = ^{ return III+JJJJ; };
-
- // rdar 7671883
- __block char array[10] = {'a', 'b', 'c', 'd'};
- char (^ch)() = ^{ array[1] = 'X'; return array[5]; };
- ch();
-
- return 0;
-}
diff --git a/test/Sema/block-misc.c b/test/Sema/block-misc.c
index 1109be6311b0..ca71ab12b268 100644
--- a/test/Sema/block-misc.c
+++ b/test/Sema/block-misc.c
@@ -214,8 +214,10 @@ void test20() {
// radr://7438948
void test21() {
int a[7]; // expected-note {{declared at}}
+ __block int b[10]; // expected-note {{declared at}}
a[1] = 1;
^{
(void)a[1]; // expected-error {{cannot refer to declaration with an array type inside block}}
+ (void)b[1]; // expected-error {{cannot refer to declaration with an array type inside block}}
}();
}
diff --git a/test/Sema/invalid-init-diag.c b/test/Sema/invalid-init-diag.c
index a215fa7c254b..dec7d6c18f8a 100644
--- a/test/Sema/invalid-init-diag.c
+++ b/test/Sema/invalid-init-diag.c
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
int a;
-struct {int x;} x = a; // expected-error {{incompatible type initializing 'int', expected 'struct <anonymous>'}}
+struct {int x;} x = a; // expected-error {{incompatible type initializing 'int', expected 'struct <anonymous}}
diff --git a/test/Sema/warn-shadow.c b/test/Sema/warn-shadow.c
new file mode 100644
index 000000000000..c9a783b437a0
--- /dev/null
+++ b/test/Sema/warn-shadow.c
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -fblocks -Wshadow %s
+
+int i; // expected-note 3 {{previous declaration is here}}
+
+void foo() {
+ int pass1;
+ int i; // expected-warning {{declaration shadows a variable in the global scope}} \
+ // expected-note {{previous declaration is here}}
+ {
+ int pass2;
+ int i; // expected-warning {{declaration shadows a local variable}} \
+ // expected-note {{previous declaration is here}}
+ {
+ int pass3;
+ int i; // expected-warning {{declaration shadows a local variable}}
+ }
+ }
+
+ int sin; // okay; 'sin' has not been declared, even though it's a builtin.
+}
+
+// <rdar://problem/7677531>
+void (^test1)(int) = ^(int i) { // expected-warning {{declaration shadows a variable in the global scope}} \
+ // expected-note{{previous declaration is here}}
+ {
+ int i; // expected-warning {{declaration shadows a local variable}} \
+ // expected-note{{previous declaration is here}}
+
+ (^(int i) { return i; })(i); //expected-warning {{declaration shadows a local variable}}
+ }
+};
+
+
+struct test2 {
+ int i;
+};
+
+void test3(void) {
+ struct test4 {
+ int i;
+ };
+}
+
+void test4(int i) { // expected-warning {{declaration shadows a variable in the global scope}}
+}
diff --git a/test/Sema/x86-intrinsics-headers.c b/test/Sema/x86-intrinsics-headers.c
index 006716ef5ba4..24c2d925e00d 100644
--- a/test/Sema/x86-intrinsics-headers.c
+++ b/test/Sema/x86-intrinsics-headers.c
@@ -21,4 +21,12 @@
#include <tmmintrin.h>
# endif
+# if defined(__SSE4_1__)
+#include <smmintrin.h>
+# endif
+
+# if defined(__SSE4_2__)
+#include <nmmintrin.h>
+# endif
+
#endif
diff --git a/test/SemaCXX/access-base-class.cpp b/test/SemaCXX/access-base-class.cpp
index eeb5f1c86fc3..25fd9e52aa25 100644
--- a/test/SemaCXX/access-base-class.cpp
+++ b/test/SemaCXX/access-base-class.cpp
@@ -63,13 +63,14 @@ namespace T6 {
class A {};
- class B : private A { // expected-note {{declared private here}}
+ class B : private A { // expected-note {{declared private here}} expected-note {{constrained by private inheritance here}}
void f(C* c);
};
class C : public B {
void f(C *c) {
- A* a = c; // expected-error {{cannot cast 'T6::C' to its private base class 'T6::A'}}
+ A* a = c; // expected-error {{cannot cast 'T6::C' to its private base class 'T6::A'}} \
+ // expected-error {{'A' is a private member of 'T6::A'}}
}
};
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index 743983cd3461..508ca4d7652a 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -118,3 +118,21 @@ struct S
void S::f() {} // expected-error {{class member cannot be redeclared}} expected-note {{previous declaration}} expected-note {{previous definition}}
void f() {} // expected-error {{class member cannot be redeclared}} expected-error {{redefinition}}
};
+
+// Don't crash on this bogus code.
+namespace pr6629 {
+ // TODO: most of these errors are spurious
+ template<class T1, class T2> struct foo :
+ bogus<foo<T1,T2> > // expected-error {{unknown template name 'bogus'}} \
+ // BOGUS expected-error {{expected '{' after base class list}} \
+ // BOGUS expected-error {{expected ';' after struct}} \
+ // BOGUS expected-error {{expected unqualified-id}} \
+ { };
+
+ template<> struct foo<unknown,unknown> { // why isn't there an error here?
+ template <typename U1, typename U2> struct bar {
+ typedef bar type;
+ static const int value = 0;
+ };
+ };
+}
diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp
index b3e862dc1b0b..daa86f62fcf0 100644
--- a/test/SemaCXX/condition.cpp
+++ b/test/SemaCXX/condition.cpp
@@ -17,7 +17,7 @@ void test() {
switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}}
while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}} expected-note{{candidate constructor (the implicit copy constructor)}}
- while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct <anonymous>' is not contextually convertible to 'bool'}} expected-note{{candidate constructor (the implicit copy constructor)}}
+ while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{not contextually convertible to 'bool'}} expected-note{{candidate constructor (the implicit copy constructor)}}
switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize}} \
// expected-warning{{enumeration value 'E' not handled in switch}}
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 4fcb0bb98dc0..accc8db6c48f 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -154,8 +154,8 @@ void test()
i1 = i1 ? i1 : ir1;
int *pi1 = i1 ? &i1 : 0;
pi1 = i1 ? 0 : &i1;
- i1 = i1 ? i1 : EVal; // expected-warning {{operands of ? are integers of different signs}} ??
- i1 = i1 ? EVal : i1; // expected-warning {{operands of ? are integers of different signs}} ??
+ i1 = i1 ? i1 : EVal;
+ i1 = i1 ? EVal : i1;
d1 = i1 ? 'c' : 4.0;
d1 = i1 ? 4.0 : 'c';
Base *pb = i1 ? (Base*)0 : (Derived*)0;
@@ -191,7 +191,7 @@ void test()
test0 = test0 ? (short) 10 : test0;
test0 = test0 ? EVal : test0;
- test0 = test0 ? EVal : (int) test0; // expected-warning {{operands of ? are integers of different signs}}
+ test0 = test0 ? EVal : (int) test0;
// Note the thing that this does not test: since DR446, various situations
// *must* create a separate temporary copy of class objects. This can only
diff --git a/test/SemaCXX/warn-shadow.cpp b/test/SemaCXX/warn-shadow.cpp
new file mode 100644
index 000000000000..509c34435560
--- /dev/null
+++ b/test/SemaCXX/warn-shadow.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wshadow %s
+
+namespace {
+ int i; // expected-note {{previous declaration is here}}
+}
+
+namespace one {
+namespace two {
+ int j; // expected-note {{previous declaration is here}}
+}
+}
+
+namespace xx {
+ int m;
+}
+namespace yy {
+ int m;
+}
+
+using namespace one::two;
+using namespace xx;
+using namespace yy;
+
+void foo() {
+ int i; // expected-warning {{declaration shadows a variable in namespace '<anonymous>'}}
+ int j; // expected-warning {{declaration shadows a variable in namespace 'one::two'}}
+ int m;
+}
+
+class A {
+ static int data; // expected-note {{previous declaration}}
+ int field; // expected-note {{previous declaration}}
+
+ void test() {
+ char *field; // expected-warning {{declaration shadows a field of 'A'}}
+ char *data; // expected-warning {{declaration shadows a static data member of 'A'}}
+ }
+};
+
+// TODO: this should warn, <rdar://problem/5018057>
+class B : A {
+ int data;
+ static int field;
+};
diff --git a/test/SemaCXX/warn-sign-compare.cpp b/test/SemaCXX/warn-sign-compare.cpp
new file mode 100644
index 000000000000..3042bfde6e06
--- /dev/null
+++ b/test/SemaCXX/warn-sign-compare.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wsign-compare %s
+
+// NOTE: When a 'enumeral mismatch' warning is implemented then expect several
+// of the following cases to be impacted.
+
+// namespace for anonymous enums tests
+namespace test1 {
+ enum { A };
+ enum { B = -1 };
+
+ template <typename T> struct Foo {
+ enum { C };
+ enum { D = ~0U };
+ };
+
+ enum { E = ~0U };
+
+ void doit_anonymous( int i ) {
+ int a1 = 1 ? i : A;
+ int a2 = 1 ? A : i;
+
+ int b1 = 1 ? i : B;
+ int b2 = 1 ? B : i;
+
+ int c1 = 1 ? i : Foo<bool>::C;
+ int c2 = 1 ? Foo<bool>::C : i;
+
+ int d1 = 1 ? i : Foo<bool>::D; // expected-warning {{operands of ? are integers of different signs}}
+ int d2 = 1 ? Foo<bool>::D : i; // expected-warning {{operands of ? are integers of different signs}}
+ int d3 = 1 ? B : Foo<bool>::D; // expected-warning {{operands of ? are integers of different signs}}
+ int d4 = 1 ? Foo<bool>::D : B; // expected-warning {{operands of ? are integers of different signs}}
+
+ int e1 = 1 ? i : E; // expected-warning {{operands of ? are integers of different signs}}
+ int e2 = 1 ? E : i; // expected-warning {{operands of ? are integers of different signs}}
+ int e3 = 1 ? E : B; // expected-warning {{operands of ? are integers of different signs}}
+ int e4 = 1 ? B : E; // expected-warning {{operands of ? are integers of different signs}}
+ }
+}
+
+// namespace for named enums tests
+namespace test2 {
+ enum Named1 { A };
+ enum Named2 { B = -1 };
+
+ template <typename T> struct Foo {
+ enum Named3 { C };
+ enum Named4 { D = ~0U };
+ };
+
+ enum Named5 { E = ~0U };
+
+ void doit_anonymous( int i ) {
+ int a1 = 1 ? i : A;
+ int a2 = 1 ? A : i;
+
+ int b1 = 1 ? i : B;
+ int b2 = 1 ? B : i;
+
+ int c1 = 1 ? i : Foo<bool>::C;
+ int c2 = 1 ? Foo<bool>::C : i;
+
+ int d1 = 1 ? i : Foo<bool>::D; // expected-warning {{operands of ? are integers of different signs}}
+ int d2 = 1 ? Foo<bool>::D : i; // expected-warning {{operands of ? are integers of different signs}}
+ int d3 = 1 ? B : Foo<bool>::D; // expected-warning {{operands of ? are integers of different signs}}
+ int d4 = 1 ? Foo<bool>::D : B; // expected-warning {{operands of ? are integers of different signs}}
+
+ int e1 = 1 ? i : E; // expected-warning {{operands of ? are integers of different signs}}
+ int e2 = 1 ? E : i; // expected-warning {{operands of ? are integers of different signs}}
+ int e3 = 1 ? E : B; // expected-warning {{operands of ? are integers of different signs}}
+ int e4 = 1 ? B : E; // expected-warning {{operands of ? are integers of different signs}}
+ }
+}
diff --git a/test/SemaObjC/block-type-safety.m b/test/SemaObjC/block-type-safety.m
new file mode 100644
index 000000000000..dab0af4026df
--- /dev/null
+++ b/test/SemaObjC/block-type-safety.m
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -fsyntax-only %s -verify -fblocks
+// test for block type safety.
+
+@interface Super @end
+@interface Sub : Super @end
+
+void f2(void(^f)(Super *)) {
+ Super *o;
+ f(o);
+}
+
+void f3(void(^f)(Sub *)) {
+ Sub *o;
+ f(o);
+}
+
+void r0(Super* (^f)()) {
+ Super *o = f();
+}
+
+void r1(Sub* (^f)()) {
+ Sub *o = f();
+}
+
+@protocol NSObject;
+
+void r2 (id<NSObject> (^f) (void)) {
+ id o = f();
+}
+
+void test1() {
+ f2(^(Sub *o) { }); // expected-error {{incompatible block pointer types passing 'void (^)(Sub *)', expected 'void (^)(Super *)'}}
+ f3(^(Super *o) { }); // OK, block taking Super* may be called with a Sub*
+
+ r0(^Super* () { return 0; }); // OK
+ r0(^Sub* () { return 0; }); // OK, variable of type Super* gets return value of type Sub*
+ r0(^id () { return 0; }); // expected-error {{incompatible block pointer types passing 'id (^)(void)', expected 'Super *(^)()'}}
+
+ r1(^Super* () { return 0; }); // expected-error {{incompatible block pointer types passing 'Super *(^)(void)', expected 'Sub *(^)()'}}
+ r1(^Sub* () { return 0; }); // OK
+ r1(^id () { return 0; }); // expected-error {{incompatible block pointer types passing 'id (^)(void)', expected 'Sub *(^)()'}}
+
+ r2(^id<NSObject>() { return 0; });
+}
+
+
+@interface A @end
+@interface B @end
+
+void f0(void (^f)(A* x)) {
+ A* a;
+ f(a);
+}
+
+void f1(void (^f)(id x)) {
+ B *b;
+ f(b);
+}
+
+void test2(void)
+{
+ f0(^(id a) { }); // OK
+ f1(^(A* a) { }); // expected-error {{incompatible block pointer types passing 'void (^)(A *)', expected 'void (^)(id)'}}
+ f1(^(id<NSObject> a) { }); // OK
+}
+
+@interface NSArray
+ // Calls block() with every object in the array
+ -enumerateObjectsWithBlock:(void (^)(id obj))block;
+@end
+
+@interface MyThing
+-(void) printThing;
+@end
+
+@implementation MyThing
+ static NSArray* myThings; // array of MyThing*
+
+ -(void) printThing { }
+
+// programmer wants to write this:
+ -printMyThings1 {
+ [myThings enumerateObjectsWithBlock: ^(MyThing *obj) { // expected-error {{incompatible block pointer types sending 'void (^)(MyThing *)', expected 'void (^)(id)'}}
+ [obj printThing];
+ }];
+ }
+
+// strict type safety requires this:
+ -printMyThings {
+ [myThings enumerateObjectsWithBlock: ^(id obj) {
+ MyThing *obj2 = (MyThing *)obj;
+ [obj2 printThing];
+ }];
+ }
+@end
+
diff --git a/test/SemaObjC/class-method-self.m b/test/SemaObjC/class-method-self.m
index 71509baf9012..6f7d1fd93f4f 100644
--- a/test/SemaObjC/class-method-self.m
+++ b/test/SemaObjC/class-method-self.m
@@ -18,9 +18,9 @@ typedef struct objc_class *Class;
static XX *obj;
+ (void)classMethod {
- [obj addObserver:self];
+ [obj addObserver:self]; // expected-warning {{incompatible pointer types sending 'Class', expected 'XX *'}}
Class whatever;
- [obj addObserver:whatever]; // GCC warns about this.
+ [obj addObserver:whatever]; // expected-warning {{incompatible pointer types sending 'Class', expected 'XX *'}}
}
@end
diff --git a/test/SemaObjC/comptypes-1.m b/test/SemaObjC/comptypes-1.m
index 24f704113d7c..5b1891d4af2e 100644
--- a/test/SemaObjC/comptypes-1.m
+++ b/test/SemaObjC/comptypes-1.m
@@ -35,7 +35,7 @@ int main()
warning, unless done from an 'id'. */
obj_c = obj; /* Ok */
obj_c = obj_cp; // // expected-warning {{incompatible pointer types assigning 'MyOtherClass *', expected 'MyClass *'}}
- obj_c = obj_C;
+ obj_c = obj_C; // expected-warning {{incompatible pointer types assigning 'Class', expected 'MyClass *'}}
/* Assigning to an 'id<MyProtocol>' variable should generate a
warning if done from a 'MyClass *' (which doesn't implement
@@ -44,7 +44,7 @@ int main()
obj_p = obj; /* Ok */
obj_p = obj_c; // expected-warning {{incompatible type assigning 'MyClass *', expected 'id<MyProtocol>'}}
obj_p = obj_cp; /* Ok */
- obj_p = obj_C; // Ok
+ obj_p = obj_C; // expected-warning {{incompatible pointer types assigning 'Class', expected 'id<MyProtocol>'}}
/* Assigning to a 'MyOtherClass *' variable should always generate
a warning, unless done from an 'id' or an 'id<MyProtocol>' (since
@@ -52,7 +52,7 @@ int main()
obj_cp = obj; /* Ok */
obj_cp = obj_c; // expected-warning {{incompatible pointer types assigning 'MyClass *', expected 'MyOtherClass *'}}
obj_cp = obj_p; /* Ok */
- obj_cp = obj_C;
+ obj_cp = obj_C; // expected-warning {{incompatible pointer types assigning 'Class', expected 'MyOtherClass *'}}
/* Any comparison involving an 'id' must be without warnings. */
if (obj == obj_p) foo() ; /* Ok */ /*Bogus warning here in 2.95.4*/
diff --git a/test/SemaObjC/id.m b/test/SemaObjC/id.m
index 98904fe1ee9c..206127a5ccef 100644
--- a/test/SemaObjC/id.m
+++ b/test/SemaObjC/id.m
@@ -9,7 +9,8 @@ void foo() {
// Test assignment compatibility of Class and id. No warning should be
// produced.
// rdar://6770142 - Class and id<foo> are compatible.
- S = T; T = S;
+ S = T; // expected-warning {{incompatible pointer types assigning 'Class', expected 'id<Foo>'}}
+ T = S; // expected-warning {{incompatible pointer types assigning 'id<Foo>', expected 'Class'}}
R = T; T = R;
R = S; S = R;
}
diff --git a/test/SemaObjC/invalid-code.m b/test/SemaObjC/invalid-code.m
index 9913a3a237c2..2f297cf6e659 100644
--- a/test/SemaObjC/invalid-code.m
+++ b/test/SemaObjC/invalid-code.m
@@ -5,3 +5,10 @@ void test1() {
void *p = @1; // expected-error {{unexpected '@' in program}}
}
+// <rdar://problem/7495713>
+// This previously triggered a crash because the class has not been defined.
+@implementation RDar7495713 (rdar_7495713_cat) // expected-error{{cannot find interface declaration for 'RDar7495713'}}
+- (id) rdar_7495713 {
+ __PRETTY_FUNCTION__; // expected-warning{{expression result unused}}
+}
+@end
diff --git a/test/SemaObjC/ivar-in-class-extension.m b/test/SemaObjC/ivar-in-class-extension.m
index 683a78feef21..e1a649cd4784 100644
--- a/test/SemaObjC/ivar-in-class-extension.m
+++ b/test/SemaObjC/ivar-in-class-extension.m
@@ -31,12 +31,12 @@ int fn3(SomeClass *obj) {
@end
@interface SomeClass (Category)
- { // expected-error {{ivar may be placed in a class extension}}
+ { // expected-error {{ivars may not be placed in categories}}
int categoryIvar;
}
@end
@interface SomeClass (Category1)
- { // expected-error {{ivar may be placed in a class extension}}
+ { // expected-error {{ivars may not be placed in categories}}
}
@end
diff --git a/test/SemaObjC/property-not-lvalue.m b/test/SemaObjC/property-not-lvalue.m
index 473ef8649fa0..55eec3e45397 100644
--- a/test/SemaObjC/property-not-lvalue.m
+++ b/test/SemaObjC/property-not-lvalue.m
@@ -15,8 +15,8 @@ typedef struct NSSize {
void foo() {
Foo *f;
- f.size.width = 2.2; // expected-error {{cannot assign to a sub-structure of an ivar using property assignment syntax}}
- f.size.inner.dim = 200; // expected-error {{cannot assign to a sub-structure of an ivar using property assignment syntax}}
+ f.size.width = 2.2; // expected-error {{expression is not assignable using property assignment syntax}}
+ f.size.inner.dim = 200; // expected-error {{expression is not assignable using property assignment syntax}}
}
// radar 7628953
@@ -28,7 +28,7 @@ void foo() {
@implementation Gorf
- (void)MyView_sharedInit {
- self.size.width = 2.2; // expected-error {{cannot assign to a sub-structure returned via a getter using property assignment syntax}}
+ self.size.width = 2.2; // expected-error {{expression is not assignable using property assignment syntax}}
}
- (NSSize)size {}
@end
diff --git a/test/SemaObjC/warn-incompatible-builtin-types.m b/test/SemaObjC/warn-incompatible-builtin-types.m
new file mode 100644
index 000000000000..2a5005a39607
--- /dev/null
+++ b/test/SemaObjC/warn-incompatible-builtin-types.m
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar 7634850
+
+@interface Foo
+- (void)foo:(Class)class;
+@end
+
+void FUNC() {
+ Class c, c1;
+ SEL s1, s2;
+ id i, i1;
+ Foo *f;
+ [f foo:f]; // expected-warning {{incompatible pointer types sending 'Foo *', expected 'Class'}}
+ c = f; // expected-warning {{incompatible pointer types assigning 'Foo *', expected 'Class'}}
+
+ c = i;
+
+ i = c;
+
+ c = c1;
+
+ i = i1;
+
+ s1 = i; // expected-warning {{incompatible pointer types assigning 'id', expected 'SEL'}}
+ i = s1; // expected-warning {{incompatible pointer types assigning 'SEL', expected 'id'}}
+
+ s1 = s2;
+
+ s1 = c; // expected-warning {{incompatible pointer types assigning 'Class', expected 'SEL'}}
+
+ c = s1; // expected-warning {{incompatible pointer types assigning 'SEL', expected 'Class'}}
+
+ f = i;
+
+ f = c; // expected-warning {{incompatible pointer types assigning 'Class', expected 'Foo *'}}
+
+ f = s1; // expected-warning {{incompatible pointer types assigning 'SEL', expected 'Foo *'}}
+
+ i = f;
+
+ s1 = f; // expected-warning {{incompatible pointer types assigning 'Foo *', expected 'SEL'}}
+}
diff --git a/test/lit.cfg b/test/lit.cfg
index beb8ae03b4f6..b306331703ea 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -119,6 +119,11 @@ def inferClang(PATH):
return clang
+# When running under valgrind, we mangle '-vg' onto the end of the triple so we
+# can check it with XFAIL and XTARGET.
+if lit.useValgrind:
+ config.target_triple += '-vg'
+
config.clang = inferClang(config.environment['PATH'])
if not lit.quiet:
lit.note('using clang: %r' % config.clang)
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 663b32fa1a06..1000818692a0 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -158,31 +158,12 @@ static RangeComparisonResult RangeCompare(SourceManager &SM,
CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
const LangOptions &LangOpts,
SourceRange R) {
- // FIXME: This is largely copy-paste from
- // TextDiagnosticPrinter::HighlightRange. When it is clear that this is what
- // we want the two routines should be refactored.
-
// We want the last character in this location, so we will adjust the
- // instantiation location accordingly.
-
- // If the location is from a macro instantiation, get the end of the
- // instantiation range.
+ // location accordingly.
+ // FIXME: How do do this with a macro instantiation location?
SourceLocation EndLoc = R.getEnd();
- SourceLocation InstLoc = SM.getInstantiationLoc(EndLoc);
- if (EndLoc.isMacroID())
- InstLoc = SM.getInstantiationRange(EndLoc).second;
-
- // Measure the length token we're pointing at, so we can adjust the physical
- // location in the file to point at the last character.
- //
- // FIXME: This won't cope with trigraphs or escaped newlines well. For that,
- // we actually need a preprocessor, which isn't currently available
- // here. Eventually, we'll switch the pointer data of
- // CXSourceLocation/CXSourceRange to a translation unit (CXXUnit), so that the
- // preprocessor will be available here. At that point, we can use
- // Preprocessor::getLocForEndOfToken().
- if (InstLoc.isValid()) {
- unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM, LangOpts);
+ if (!EndLoc.isInvalid() && EndLoc.isFileID()) {
+ unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts);
EndLoc = EndLoc.getFileLocWithOffset(Length);
}
@@ -253,6 +234,10 @@ public:
}
bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
+
+ std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ getPreprocessedEntities();
+
bool VisitChildren(CXCursor Parent);
// Declaration visitors
@@ -371,6 +356,48 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
return false;
}
+std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+CursorVisitor::getPreprocessedEntities() {
+ PreprocessingRecord &PPRec
+ = *TU->getPreprocessor().getPreprocessingRecord();
+
+ bool OnlyLocalDecls
+ = !TU->isMainFileAST() && TU->getOnlyLocalDecls();
+
+ // There is no region of interest; we have to walk everything.
+ if (RegionOfInterest.isInvalid())
+ return std::make_pair(PPRec.begin(OnlyLocalDecls),
+ PPRec.end(OnlyLocalDecls));
+
+ // Find the file in which the region of interest lands.
+ SourceManager &SM = TU->getSourceManager();
+ std::pair<FileID, unsigned> Begin
+ = SM.getDecomposedInstantiationLoc(RegionOfInterest.getBegin());
+ std::pair<FileID, unsigned> End
+ = SM.getDecomposedInstantiationLoc(RegionOfInterest.getEnd());
+
+ // The region of interest spans files; we have to walk everything.
+ if (Begin.first != End.first)
+ return std::make_pair(PPRec.begin(OnlyLocalDecls),
+ PPRec.end(OnlyLocalDecls));
+
+ ASTUnit::PreprocessedEntitiesByFileMap &ByFileMap
+ = TU->getPreprocessedEntitiesByFile();
+ if (ByFileMap.empty()) {
+ // Build the mapping from files to sets of preprocessed entities.
+ for (PreprocessingRecord::iterator E = PPRec.begin(OnlyLocalDecls),
+ EEnd = PPRec.end(OnlyLocalDecls);
+ E != EEnd; ++E) {
+ std::pair<FileID, unsigned> P
+ = SM.getDecomposedInstantiationLoc((*E)->getSourceRange().getBegin());
+ ByFileMap[P.first].push_back(*E);
+ }
+ }
+
+ return std::make_pair(ByFileMap[Begin.first].begin(),
+ ByFileMap[Begin.first].end());
+}
+
/// \brief Visit the children of the given cursor.
///
/// \returns true if the visitation should be aborted, false if it
@@ -425,11 +452,31 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
if (Visit(MakeCXCursor(*it, CXXUnit), true))
return true;
}
- } else {
- return VisitDeclContext(
- CXXUnit->getASTContext().getTranslationUnitDecl());
- }
+ } else if (VisitDeclContext(
+ CXXUnit->getASTContext().getTranslationUnitDecl()))
+ return true;
+ // Walk the preprocessing record.
+ if (CXXUnit->getPreprocessor().getPreprocessingRecord()) {
+ // FIXME: Once we have the ability to deserialize a preprocessing record,
+ // do so.
+ PreprocessingRecord::iterator E, EEnd;
+ for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) {
+ if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
+ if (Visit(MakeMacroInstantiationCursor(MI, CXXUnit)))
+ return true;
+
+ continue;
+ }
+
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
+ if (Visit(MakeMacroDefinitionCursor(MD, CXXUnit)))
+ return true;
+
+ continue;
+ }
+ }
+ }
return false;
}
@@ -601,9 +648,10 @@ bool CursorVisitor::VisitObjCImplDecl(ObjCImplDecl *D) {
}
bool CursorVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
- if (Visit(MakeCursorObjCClassRef(D->getCategoryDecl()->getClassInterface(),
- D->getLocation(), TU)))
- return true;
+ // 'ID' could be null when dealing with invalid code.
+ if (ObjCInterfaceDecl *ID = D->getClassInterface())
+ if (Visit(MakeCursorObjCClassRef(ID, D->getLocation(), TU)))
+ return true;
return VisitObjCImplDecl(D);
}
@@ -994,7 +1042,8 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
Args.push_back(source_filename);
Args.insert(Args.end(), command_line_args,
command_line_args + num_command_line_args);
-
+ Args.push_back("-Xclang");
+ Args.push_back("-detailed-preprocessing-record");
unsigned NumErrors = Diags->getNumErrors();
#ifdef USE_CRASHTRACER
@@ -1093,6 +1142,9 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
TemporaryFiles.push_back(DiagnosticsFile);
argv.push_back("-fdiagnostics-binary");
+ argv.push_back("-Xclang");
+ argv.push_back("-detailed-preprocessing-record");
+
// Add the null terminator.
argv.push_back(NULL);
@@ -1438,6 +1490,14 @@ CXString clang_getCursorSpelling(CXCursor C) {
return createCXString("");
}
+ if (C.kind == CXCursor_MacroInstantiation)
+ return createCXString(getCursorMacroInstantiation(C)->getName()
+ ->getNameStart());
+
+ if (C.kind == CXCursor_MacroDefinition)
+ return createCXString(getCursorMacroDefinition(C)->getName()
+ ->getNameStart());
+
if (clang_isDeclaration(C.kind))
return getDeclSpelling(getCursorDecl(C));
@@ -1508,6 +1568,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("UnexposedStmt");
case CXCursor_InvalidFile:
return createCXString("InvalidFile");
+ case CXCursor_InvalidCode:
+ return createCXString("InvalidCode");
case CXCursor_NoDeclFound:
return createCXString("NoDeclFound");
case CXCursor_NotImplemented:
@@ -1518,8 +1580,14 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("UnexposedAttr");
case CXCursor_IBActionAttr:
return createCXString("attribute(ibaction)");
- case CXCursor_IBOutletAttr:
- return createCXString("attribute(iboutlet)");
+ case CXCursor_IBOutletAttr:
+ return createCXString("attribute(iboutlet)");
+ case CXCursor_PreprocessingDirective:
+ return createCXString("preprocessing directive");
+ case CXCursor_MacroDefinition:
+ return createCXString("macro definition");
+ case CXCursor_MacroInstantiation:
+ return createCXString("macro instantiation");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -1590,6 +1658,10 @@ unsigned clang_isTranslationUnit(enum CXCursorKind K) {
return K == CXCursor_TranslationUnit;
}
+unsigned clang_isPreprocessing(enum CXCursorKind K) {
+ return K >= CXCursor_FirstPreprocessing && K <= CXCursor_LastPreprocessing;
+}
+
unsigned clang_isUnexposed(enum CXCursorKind K) {
switch (K) {
case CXCursor_UnexposedDecl:
@@ -1642,6 +1714,22 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(getCursorContext(C),
getLocationFromExpr(getCursorExpr(C)));
+ if (C.kind == CXCursor_PreprocessingDirective) {
+ SourceLocation L = cxcursor::getCursorPreprocessingDirective(C).getBegin();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
+ if (C.kind == CXCursor_MacroInstantiation) {
+ SourceLocation L
+ = cxcursor::getCursorMacroInstantiation(C)->getSourceRange().getBegin();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
+ if (C.kind == CXCursor_MacroDefinition) {
+ SourceLocation L = cxcursor::getCursorMacroDefinition(C)->getLocation();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
if (!getCursorDecl(C))
return clang_getNullLocation();
@@ -1693,6 +1781,21 @@ CXSourceRange clang_getCursorExtent(CXCursor C) {
return cxloc::translateSourceRange(getCursorContext(C),
getCursorStmt(C)->getSourceRange());
+ if (C.kind == CXCursor_PreprocessingDirective) {
+ SourceRange R = cxcursor::getCursorPreprocessingDirective(C);
+ return cxloc::translateSourceRange(getCursorContext(C), R);
+ }
+
+ if (C.kind == CXCursor_MacroInstantiation) {
+ SourceRange R = cxcursor::getCursorMacroInstantiation(C)->getSourceRange();
+ return cxloc::translateSourceRange(getCursorContext(C), R);
+ }
+
+ if (C.kind == CXCursor_MacroDefinition) {
+ SourceRange R = cxcursor::getCursorMacroDefinition(C)->getSourceRange();
+ return cxloc::translateSourceRange(getCursorContext(C), R);
+ }
+
if (!getCursorDecl(C))
return clang_getNullRange();
@@ -1715,6 +1818,11 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
return clang_getNullCursor();
}
+ if (C.kind == CXCursor_MacroInstantiation) {
+ if (MacroDefinition *Def = getCursorMacroInstantiation(C)->getDefinition())
+ return MakeMacroDefinitionCursor(Def, CXXUnit);
+ }
+
if (!clang_isReference(C.kind))
return clang_getNullCursor();
@@ -1753,6 +1861,9 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
WasReference = true;
}
+ if (C.kind == CXCursor_MacroInstantiation)
+ return clang_getCursorReferenced(C);
+
if (!clang_isDeclaration(C.kind))
return clang_getNullCursor();
@@ -2101,6 +2212,8 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
bool Invalid = false;
llvm::StringRef Buffer
= SourceMgr.getBufferData(BeginLocInfo.first, &Invalid);
+ if (Invalid)
+ return;
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
CXXUnit->getASTContext().getLangOptions(),
@@ -2188,6 +2301,8 @@ enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
return CXChildVisit_Recurse;
// Okay: we can annotate the location of this expression
+ } else if (clang_isPreprocessing(cursor.kind)) {
+ // We can always annotate a preprocessing directive/macro instantiation.
} else {
// Nothing to annotate
return CXChildVisit_Recurse;
@@ -2214,31 +2329,94 @@ void clang_annotateTokens(CXTranslationUnit TU,
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
- // Annotate all of the source locations in the region of interest that map
+ // Determine the region of interest, which contains all of the tokens.
SourceRange RegionOfInterest;
RegionOfInterest.setBegin(
cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0])));
SourceLocation End
- = cxloc::translateSourceLocation(clang_getTokenLocation(TU,
- Tokens[NumTokens - 1]));
+ = cxloc::translateSourceLocation(clang_getTokenLocation(TU,
+ Tokens[NumTokens - 1]));
RegionOfInterest.setEnd(CXXUnit->getPreprocessor().getLocForEndOfToken(End));
- // FIXME: Would be great to have a "hint" cursor, then walk from that
- // hint cursor upward until we find a cursor whose source range encloses
- // the region of interest, rather than starting from the translation unit.
+
+ // A mapping from the source locations found when re-lexing or traversing the
+ // region of interest to the corresponding cursors.
AnnotateTokensData Annotated;
+
+ // Relex the tokens within the source range to look for preprocessing
+ // directives.
+ SourceManager &SourceMgr = CXXUnit->getSourceManager();
+ std::pair<FileID, unsigned> BeginLocInfo
+ = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
+ std::pair<FileID, unsigned> EndLocInfo
+ = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
+
+ llvm::StringRef Buffer;
+ bool Invalid = false;
+ if (BeginLocInfo.first == EndLocInfo.first &&
+ ((Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid)),true) &&
+ !Invalid) {
+ Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
+ CXXUnit->getASTContext().getLangOptions(),
+ Buffer.begin(), Buffer.data() + BeginLocInfo.second,
+ Buffer.end());
+ Lex.SetCommentRetentionState(true);
+
+ // Lex tokens in raw mode until we hit the end of the range, to avoid
+ // entering #includes or expanding macros.
+ while (true) {
+ Token Tok;
+ Lex.LexFromRawLexer(Tok);
+
+ reprocess:
+ if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
+ // We have found a preprocessing directive. Gobble it up so that we
+ // don't see it while preprocessing these tokens later, but keep track of
+ // all of the token locations inside this preprocessing directive so that
+ // we can annotate them appropriately.
+ //
+ // FIXME: Some simple tests here could identify macro definitions and
+ // #undefs, to provide specific cursor kinds for those.
+ std::vector<SourceLocation> Locations;
+ do {
+ Locations.push_back(Tok.getLocation());
+ Lex.LexFromRawLexer(Tok);
+ } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof));
+
+ using namespace cxcursor;
+ CXCursor Cursor
+ = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
+ Locations.back()),
+ CXXUnit);
+ for (unsigned I = 0, N = Locations.size(); I != N; ++I) {
+ Annotated[Locations[I].getRawEncoding()] = Cursor;
+ }
+
+ if (Tok.isAtStartOfLine())
+ goto reprocess;
+
+ continue;
+ }
+
+ if (Tok.is(tok::eof))
+ break;
+ }
+ }
+
+ // Annotate all of the source locations in the region of interest that map to
+ // a specific cursor.
CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit);
CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated,
Decl::MaxPCHLevel, RegionOfInterest);
AnnotateVis.VisitChildren(Parent);
-
+
for (unsigned I = 0; I != NumTokens; ++I) {
// Determine whether we saw a cursor at this token's location.
AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
if (Pos == Annotated.end())
continue;
-
+
Cursors[I] = Pos->second;
- }
+ }
}
void clang_disposeTokens(CXTranslationUnit TU,
@@ -2254,6 +2432,9 @@ void clang_disposeTokens(CXTranslationUnit TU,
extern "C" {
CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
+ if (!clang_isDeclaration(cursor.kind))
+ return CXLinkage_Invalid;
+
Decl *D = cxcursor::getCursorDecl(cursor);
if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
switch (ND->getLinkage()) {
diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports
index fe0396d2b140..d036e5cfd8f2 100644
--- a/tools/CIndex/CIndex.exports
+++ b/tools/CIndex/CIndex.exports
@@ -70,6 +70,7 @@ _clang_isCursorDefinition
_clang_isDeclaration
_clang_isExpression
_clang_isInvalid
+_clang_isPreprocessing
_clang_isReference
_clang_isStatement
_clang_isTranslationUnit
diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp
index 9dbbd3541e4c..8521971a3065 100644
--- a/tools/CIndex/CIndexUSRs.cpp
+++ b/tools/CIndex/CIndexUSRs.cpp
@@ -155,14 +155,30 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
break;
case Decl::ObjCCategory: {
ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
- GenObjCCategory(CD->getClassInterface()->getName(),
- CD->getName());
+ ObjCInterfaceDecl *ID = CD->getClassInterface();
+ if (!ID) {
+ // Handle invalid code where the @interface might not
+ // have been specified.
+ // FIXME: We should be able to generate this USR even if the
+ // @interface isn't available.
+ IgnoreResults = true;
+ return;
+ }
+ GenObjCCategory(ID->getName(), CD->getName());
break;
}
case Decl::ObjCCategoryImpl: {
ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
- GenObjCCategory(CD->getClassInterface()->getName(),
- CD->getName());
+ ObjCInterfaceDecl *ID = CD->getClassInterface();
+ if (!ID) {
+ // Handle invalid code where the @interface might not
+ // have been specified.
+ // FIXME: We should be able to generate this USR even if the
+ // @interface isn't available.
+ IgnoreResults = true;
+ return;
+ }
+ GenObjCCategory(ID->getName(), CD->getName());
break;
}
case Decl::ObjCProtocol:
@@ -251,7 +267,7 @@ CXString clang_getCursorUSR(CXCursor C) {
SUG->Visit(static_cast<Decl*>(D));
if (SUG->ignoreResults() || SUG.str().empty())
- return createCXString(NULL);
+ return createCXString("");
// Return a copy of the string that must be disposed by the caller.
return createCXString(SUG.str(), true);
diff --git a/tools/CIndex/CXCursor.cpp b/tools/CIndex/CXCursor.cpp
index 0fa73a513da4..cbf9d7e6f919 100644
--- a/tools/CIndex/CXCursor.cpp
+++ b/tools/CIndex/CXCursor.cpp
@@ -266,7 +266,10 @@ cxcursor::getCursorObjCProtocolRef(CXCursor C) {
CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
SourceLocation Loc,
ASTUnit *TU) {
- assert(Class && TU && "Invalid arguments!");
+ // 'Class' can be null for invalid code.
+ if (!Class)
+ return MakeCXCursorInvalid(CXCursor_InvalidCode);
+ assert(TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
CXCursor C = { CXCursor_ObjCClassRef, { Class, RawLoc, TU } };
return C;
@@ -296,6 +299,45 @@ cxcursor::getCursorTypeRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
+CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range,
+ ASTUnit *TU) {
+ CXCursor C = { CXCursor_PreprocessingDirective,
+ { reinterpret_cast<void *>(Range.getBegin().getRawEncoding()),
+ reinterpret_cast<void *>(Range.getEnd().getRawEncoding()),
+ TU }
+ };
+ return C;
+}
+
+SourceRange cxcursor::getCursorPreprocessingDirective(CXCursor C) {
+ assert(C.kind == CXCursor_PreprocessingDirective);
+ return SourceRange(SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t> (C.data[0])),
+ SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t> (C.data[1])));
+}
+
+CXCursor cxcursor::MakeMacroDefinitionCursor(MacroDefinition *MI, ASTUnit *TU) {
+ CXCursor C = { CXCursor_MacroDefinition, { MI, 0, TU } };
+ return C;
+}
+
+MacroDefinition *cxcursor::getCursorMacroDefinition(CXCursor C) {
+ assert(C.kind == CXCursor_MacroDefinition);
+ return static_cast<MacroDefinition *>(C.data[0]);
+}
+
+CXCursor cxcursor::MakeMacroInstantiationCursor(MacroInstantiation *MI,
+ ASTUnit *TU) {
+ CXCursor C = { CXCursor_MacroInstantiation, { MI, 0, TU } };
+ return C;
+}
+
+MacroInstantiation *cxcursor::getCursorMacroInstantiation(CXCursor C) {
+ assert(C.kind == CXCursor_MacroInstantiation);
+ return static_cast<MacroInstantiation *>(C.data[0]);
+}
+
Decl *cxcursor::getCursorDecl(CXCursor Cursor) {
return (Decl *)Cursor.data[0];
}
diff --git a/tools/CIndex/CXCursor.h b/tools/CIndex/CXCursor.h
index 934d5e2aebd3..1664f5a9ced2 100644
--- a/tools/CIndex/CXCursor.h
+++ b/tools/CIndex/CXCursor.h
@@ -25,6 +25,8 @@ class ASTUnit;
class Attr;
class Decl;
class Expr;
+class MacroDefinition;
+class MacroInstantiation;
class NamedDecl;
class ObjCInterfaceDecl;
class ObjCProtocolDecl;
@@ -73,6 +75,26 @@ CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, ASTUnit *TU);
/// and optionally the location where the reference occurred.
std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C);
+/// \brief Create a preprocessing directive cursor.
+CXCursor MakePreprocessingDirectiveCursor(SourceRange Range, ASTUnit *TU);
+
+/// \brief Unpack a given preprocessing directive to retrieve its source range.
+SourceRange getCursorPreprocessingDirective(CXCursor C);
+
+/// \brief Create a macro definition cursor.
+CXCursor MakeMacroDefinitionCursor(MacroDefinition *, ASTUnit *TU);
+
+/// \brief Unpack a given macro definition cursor to retrieve its
+/// source range.
+MacroDefinition *getCursorMacroDefinition(CXCursor C);
+
+/// \brief Create a macro instantiation cursor.
+CXCursor MakeMacroInstantiationCursor(MacroInstantiation *, ASTUnit *TU);
+
+/// \brief Unpack a given macro instantiation cursor to retrieve its
+/// source range.
+MacroInstantiation *getCursorMacroInstantiation(CXCursor C);
+
Decl *getCursorDecl(CXCursor Cursor);
Expr *getCursorExpr(CXCursor Cursor);
Stmt *getCursorStmt(CXCursor Cursor);
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 294a68015f4e..0b108aef130e 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -74,6 +74,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case GeneratePCH: return new GeneratePCHAction();
case GeneratePTH: return new GeneratePTHAction();
case InheritanceView: return new InheritanceViewAction();
+ case InitOnly: return new InitOnlyAction();
case ParseNoop: return new ParseOnlyAction();
case ParsePrintCallbacks: return new PrintParseAction();
case ParseSyntaxOnly: return new SyntaxOnlyAction();
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 46f412403167..2108c8fbdbfe 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -218,6 +218,11 @@ int main(int argc, const char **argv) {
llvm::OwningPtr<Compilation> C;
+ // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
+ TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
+ if (TheDriver.CCPrintOptions)
+ TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
+
// Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a
// command line behind the scenes.
std::set<std::string> SavedStrings;
diff --git a/www/cxx_compatibility.html b/www/cxx_compatibility.html
new file mode 100644
index 000000000000..e5fd63ef9c97
--- /dev/null
+++ b/www/cxx_compatibility.html
@@ -0,0 +1,244 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - C++ Compatibility</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+ <style type="text/css">
+</style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<!-- ======================================================================= -->
+<h1>Clang's C++ Compatibility</h1>
+<!-- ======================================================================= -->
+
+<ul>
+<li><a href="#intro">Introduction</a></li>
+<li><a href="#vla">Variable-length arrays</a></li>
+<li><a href="#init_static_const">Initialization of non-integral static const data members within a class definition</a></li>
+<li><a href="#dep_lookup">Unqualified lookup in templates</a></li>
+<li><a href="#dep_lookup_bases">Unqualified lookup into dependent bases of class templates</a></li>
+<li><a href="#default_init_const">Default initialization of const variable of a class type requires user-defined default constructor</a></li>
+</ul>
+
+<!-- ======================================================================= -->
+<h2 id="intro">Introduction</h2>
+<!-- ======================================================================= -->
+
+<p>Clang strives to strictly conform to the C++ standard. That means
+it will reject invalid C++ code that another compiler may accept.
+This page helps you decide whether a Clang error message means a
+C++-conformance bug in your code and how you can fix it.</p>
+
+<!-- ======================================================================= -->
+<h2 id="vla">Variable-length arrays</h2>
+<!-- ======================================================================= -->
+
+<p>GCC allows an array's size to be determined at run time. This,
+however, is not standard C++. Furthermore, it is a potential security
+hole as an incorrect array size may overflow the stack. If Clang tells
+you <tt>"variable length arrays are not permitted in C++"</tt>, here
+are some ways in which you can fix it:</p>
+
+<ol>
+<li>replace it with a fixed-size array if you can determine a
+ reasonable upper bound at compile time; sometimes this is as
+ simple as changing <tt>int size = ...;</tt> to <tt>const int size
+ = ...;</tt> (if the definition of <tt>size</tt> is a compile-time
+ integral constant);</li>
+<li>use an <tt>std::string</tt> instead of a <tt>char []</tt>;</li>
+<li>use <tt>std::vector</tt> or some other suitable container type;
+ or</li>
+<li>allocate the array on the heap instead using <tt>new Type[]</tt> -
+ just remember to <tt>delete[]</tt> it.</li>
+</ol>
+
+<!-- ======================================================================= -->
+<h2 id="init_static_const">Initialization of non-integral static const data members within a class definition</h2>
+<!-- ======================================================================= -->
+
+The following code is ill-formed in C++'03:
+
+<pre>
+class SomeClass {
+ public:
+ static const double SomeConstant = 0.5;
+};
+
+const double SomeClass::SomeConstant;
+</pre>
+
+Clang errors with something similar to:
+
+<pre>
+.../your_file.h:42:42: error: 'SomeConstant' can only be initialized if it is a static const integral data member
+ static const double SomeConstant = 0.5;
+ ^ ~~~
+</pre>
+
+Only <i>integral</i> constant expressions are allowed as initializers
+within the class definition. See C++'03 [class.static.data] p4 for the
+details of this restriction. The fix here is straightforward: move
+the initializer to the definition of the static data member, which
+must exist outside of the class definition:
+
+<pre>
+class SomeClass {
+ public:
+ static const double SomeConstant;
+};
+
+const double SomeClass::SomeConstant<b> = 0.5</b>;
+</pre>
+
+Note that the forthcoming C++0x standard will allow this.
+
+<!-- ======================================================================= -->
+<h2 id="dep_lookup">Unqualified lookup in templates</h2>
+<!-- ======================================================================= -->
+
+Some versions of GCC accept the following invalid code:
+
+<pre>
+template &lt;typename T&gt; struct Foo {
+ void Work(T x) {
+ func(x);
+ }
+};
+...
+void func(int x);
+...
+template struct Foo&lt;int&gt;; // or anything else that instantiates Foo&lt;int&gt;::Work
+</pre>
+
+The standard says that unqualified names like <tt>func</tt> are looked up
+when the template is defined, not when it's instantiated. Since
+<tt>void func(int)</tt> was not declared yet when <tt>Foo</tt> was
+defined, it's not considered. The fix is usually to
+declare <tt>func</tt> before <tt>Foo</tt>.
+
+<p>This is complicated by <i>argument-dependent lookup</i> (ADL),
+which is done when unqualified names are called as functions,
+like <tt>func(x)</tt> above. The standard says that ADL is performed
+in both places if any of the arguments are type-dependent, like
+<tt>x</tt> is in this example. However, ADL does nothing for builtin
+types like <tt>int</tt>, so the example is still invalid. See
+[basic.lookup.argdep] for more information.
+
+<!-- ======================================================================= -->
+<h2 id="dep_lookup_bases">Unqualified lookup into dependent bases of class templates</h2>
+<!-- ======================================================================= -->
+
+Some versions of GCC accept the following invalid code:
+
+<pre>
+template &lt;typename T&gt; struct Base {
+ void DoThis(T x) {}
+ static void DoThat(T x) {}
+};
+
+template &lt;typename T&gt; struct Derived : public Base&lt;T&gt; {
+ void Work(T x) {
+ DoThis(x); // Invalid!
+ DoThat(x); // Invalid!
+ }
+};
+</pre>
+
+Clang correctly rejects it with the following errors
+(when <tt>Derived</tt> is eventually instantiated):
+
+<pre>
+my_file.cpp:8:5: error: use of undeclared identifier 'DoThis'
+ DoThis(x);
+ ^
+ this-&gt;
+my_file.cpp:2:8: note: must qualify identifier to find this declaration in dependent base class
+ void DoThis(T x) {}
+ ^
+my_file.cpp:9:5: error: use of undeclared identifier 'DoThat'
+ DoThat(x);
+ ^
+ this-&gt;
+my_file.cpp:3:15: note: must qualify identifier to find this declaration in dependent base class
+ static void DoThat(T x) {}
+</pre>
+
+Like we said <a href="#dep_lookup">above</a>, unqualified names like
+<tt>DoThis</tt> and <tt>DoThat</tt> are looked up when the template
+<tt>Derived</tt> is defined, not when it's instantiated. When we look
+up a name used in a class, we usually look into the base classes.
+However, we can't look into the base class <tt>Base&lt;T&gt;</tt>
+because its type depends on the template argument <tt>T</tt>, so the
+standard says we should just ignore it. See [temp.dep]p3 for details.
+
+<p>The fix, as Clang tells you, is to tell the compiler that we want a
+class member by prefixing the calls with <tt>this-&gt;</tt>:
+
+<pre>
+ void Work(T x) {
+ <b>this-&gt;</b>DoThis(x);
+ <b>this-&gt;</b>DoThat(x);
+ }
+</pre>
+
+Alternatively, you can tell the compiler exactly where to look:
+
+<pre>
+ void Work(T x) {
+ <b>Base&lt;T&gt;</b>::DoThis(x);
+ <b>Base&lt;T&gt;</b>::DoThat(x);
+ }
+</pre>
+
+This works whether the methods are static or not, but be careful:
+if <tt>DoThis</tt> is virtual, calling it this way will bypass virtual
+dispatch!
+
+<!-- ======================================================================= -->
+<h2 id="default_init_const">Default initialization of const variable of a class type requires user-defined default constructor</h2>
+<!-- ======================================================================= -->
+
+If a <tt>class</tt> or <tt>struct</tt> has no user-defined default
+constructor, C++ doesn't allow you to default construct a <tt>const</tt>
+instance of it like this ([dcl.init], p9):
+
+<pre>
+class Foo {
+ public:
+ // The compiler-supplied default constructor works fine, so we
+ // don't bother with defining one.
+ ...
+};
+
+void Bar() {
+ const Foo foo; // Error!
+ ...
+}
+</pre>
+
+To fix this, you can define a default constructor for the class:
+
+<pre>
+class Foo {
+ public:
+ Foo() {}
+ ...
+};
+
+void Bar() {
+ const Foo foo; // Now the compiler is happy.
+ ...
+}
+</pre>
+
+</div>
+</body>
+</html>