aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile8
-rw-r--r--clang.xcodeproj/project.pbxproj4
-rw-r--r--include/clang-c/Index.h115
-rw-r--r--include/clang/AST/ASTContext.h3
-rw-r--r--include/clang/AST/Decl.h120
-rw-r--r--include/clang/AST/DeclBase.h2
-rw-r--r--include/clang/AST/DeclCXX.h101
-rw-r--r--include/clang/AST/DeclFriend.h167
-rw-r--r--include/clang/AST/DeclObjC.h14
-rw-r--r--include/clang/AST/DeclVisitor.h1
-rw-r--r--include/clang/AST/RecordLayout.h16
-rw-r--r--include/clang/Analysis/CFG.h3
-rw-r--r--include/clang/Basic/Builtins.def4
-rw-r--r--include/clang/Basic/BuiltinsX86.def6
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td8
-rw-r--r--include/clang/Basic/DiagnosticGroups.td3
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td49
-rw-r--r--include/clang/Basic/IdentifierTable.h29
-rw-r--r--include/clang/Basic/LangOptions.h3
-rw-r--r--include/clang/Basic/PartialDiagnostic.h4
-rw-r--r--include/clang/Basic/SourceLocation.h7
-rw-r--r--include/clang/Basic/SourceManager.h73
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h5
-rw-r--r--include/clang/Driver/Action.h12
-rw-r--r--include/clang/Driver/ArgList.h2
-rw-r--r--include/clang/Driver/CC1Options.td2
-rw-r--r--include/clang/Driver/Job.h4
-rw-r--r--include/clang/Frontend/ASTUnit.h2
-rw-r--r--include/clang/Lex/PTHManager.h2
-rw-r--r--include/clang/Lex/Preprocessor.h18
-rw-r--r--lib/AST/ASTContext.cpp70
-rw-r--r--lib/AST/ASTImporter.cpp28
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/Decl.cpp75
-rw-r--r--lib/AST/DeclBase.cpp1
-rw-r--r--lib/AST/DeclCXX.cpp256
-rw-r--r--lib/AST/DeclFriend.cpp41
-rw-r--r--lib/AST/DeclObjC.cpp104
-rw-r--r--lib/AST/Expr.cpp10
-rw-r--r--lib/AST/Makefile2
-rw-r--r--lib/AST/RecordLayout.cpp37
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp400
-rw-r--r--lib/AST/RecordLayoutBuilder.h58
-rw-r--r--lib/AST/TypePrinter.cpp7
-rw-r--r--lib/Analysis/Makefile2
-rw-r--r--lib/Basic/IdentifierTable.cpp29
-rw-r--r--lib/Basic/SourceLocation.cpp5
-rw-r--r--lib/Basic/SourceManager.cpp151
-rw-r--r--lib/Basic/Targets.cpp1
-rw-r--r--lib/Checker/GRExprEngine.cpp82
-rw-r--r--lib/Checker/Makefile2
-rw-r--r--lib/Checker/RegionStore.cpp76
-rw-r--r--lib/CodeGen/CGClass.cpp8
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp35
-rw-r--r--lib/CodeGen/CGDecl.cpp126
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp4
-rw-r--r--lib/CodeGen/CGRTTI.cpp2
-rw-r--r--lib/CodeGen/CGVtable.cpp479
-rw-r--r--lib/CodeGen/CGVtable.h20
-rw-r--r--lib/CodeGen/CodeGenModule.cpp23
-rw-r--r--lib/CodeGen/CodeGenModule.h3
-rw-r--r--lib/CodeGen/Makefile4
-rw-r--r--lib/CodeGen/Mangle.cpp173
-rw-r--r--lib/CodeGen/TargetInfo.cpp94
-rw-r--r--lib/Driver/Action.cpp6
-rw-r--r--lib/Driver/ArgList.cpp27
-rw-r--r--lib/Driver/Driver.cpp5
-rw-r--r--lib/Driver/Job.cpp10
-rw-r--r--lib/Frontend/ASTUnit.cpp9
-rw-r--r--lib/Frontend/CacheTokens.cpp34
-rw-r--r--lib/Frontend/CompilerInstance.cpp4
-rw-r--r--lib/Frontend/CompilerInvocation.cpp3
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp34
-rw-r--r--lib/Frontend/Makefile2
-rw-r--r--lib/Frontend/PCHReader.cpp2
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp7
-rw-r--r--lib/Frontend/PCHWriter.cpp47
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp9
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp2
-rw-r--r--lib/Frontend/RewriteMacros.cpp2
-rw-r--r--lib/Frontend/RewriteObjC.cpp169
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp20
-rw-r--r--lib/Headers/smmintrin.h137
-rw-r--r--lib/Index/Entity.cpp8
-rw-r--r--lib/Index/GlobalSelector.cpp8
-rw-r--r--lib/Index/Makefile4
-rw-r--r--lib/Lex/Lexer.cpp10
-rw-r--r--lib/Lex/LiteralSupport.cpp15
-rw-r--r--lib/Lex/Makefile4
-rw-r--r--lib/Lex/PPDirectives.cpp10
-rw-r--r--lib/Lex/PPExpressions.cpp12
-rw-r--r--lib/Lex/PPLexerChange.cpp5
-rw-r--r--lib/Lex/PTHLexer.cpp10
-rw-r--r--lib/Lex/Preprocessor.cpp81
-rw-r--r--lib/Lex/TokenLexer.cpp13
-rw-r--r--lib/Parse/Makefile2
-rw-r--r--lib/Parse/ParseDeclCXX.cpp94
-rw-r--r--lib/Parse/ParseObjc.cpp4
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp7
-rw-r--r--lib/Rewrite/Makefile2
-rw-r--r--lib/Rewrite/Rewriter.cpp4
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/Makefile2
-rw-r--r--lib/Sema/Sema.h165
-rw-r--r--lib/Sema/SemaAccess.cpp207
-rw-r--r--lib/Sema/SemaCXXCast.cpp8
-rw-r--r--lib/Sema/SemaChecking.cpp58
-rw-r--r--lib/Sema/SemaCodeComplete.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp24
-rw-r--r--lib/Sema/SemaDeclAttr.cpp16
-rw-r--r--lib/Sema/SemaDeclCXX.cpp167
-rw-r--r--lib/Sema/SemaDeclObjC.cpp1004
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp6
-rw-r--r--lib/Sema/SemaExpr.cpp353
-rw-r--r--lib/Sema/SemaExprCXX.cpp2
-rw-r--r--lib/Sema/SemaExprObjC.cpp2
-rw-r--r--lib/Sema/SemaInit.cpp22
-rw-r--r--lib/Sema/SemaLookup.cpp107
-rw-r--r--lib/Sema/SemaObjCProperty.cpp1085
-rw-r--r--lib/Sema/SemaOverload.cpp23
-rw-r--r--lib/Sema/SemaStmt.cpp7
-rw-r--r--lib/Sema/SemaTemplate.cpp11
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp64
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp175
-rw-r--r--lib/Sema/TreeTransform.h96
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp57
-rw-r--r--test/CXX/class.access/p4.cpp116
-rw-r--r--test/CXX/temp/temp.res/temp.local/p7.cpp10
-rw-r--r--test/CXX/temp/temp.res/temp.local/p8.cpp53
-rw-r--r--test/CXX/temp/temp.res/temp.local/p9.cpp15
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp4
-rw-r--r--test/CodeGen/varargs.c11
-rw-r--r--test/CodeGenCXX/PR6474.cpp2
-rw-r--r--test/CodeGenCXX/explicit-instantiation.cpp4
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp10
-rw-r--r--test/CodeGenCXX/mangle-template.cpp4
-rw-r--r--test/CodeGenCXX/mangle.cpp57
-rw-r--r--test/CodeGenCXX/member-templates.cpp4
-rw-r--r--test/CodeGenCXX/template-linkage.cpp10
-rw-r--r--test/CodeGenCXX/temporaries.cpp2
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp193
-rw-r--r--test/PCH/changed-files.c11
-rw-r--r--test/Parser/missing-end.m7
-rw-r--r--test/Rewriter/rewrite-local-externs-in-block.mm23
-rw-r--r--test/Rewriter/rewrite-super-message.mm20
-rw-r--r--test/Sema/compare.c8
-rw-r--r--test/Sema/missing-field-initializers.c50
-rw-r--r--test/Sema/overloadable.c11
-rw-r--r--test/Sema/return.c2
-rw-r--r--test/Sema/warn-unused-value.c53
-rw-r--r--test/Sema/warn-write-strings.c4
-rw-r--r--test/SemaCXX/PR6562.cpp10
-rw-r--r--test/SemaCXX/decl-expr-ambiguity.cpp2
-rw-r--r--test/SemaCXX/warn-unused-value.cpp17
-rw-r--r--test/SemaObjC/duplicate-property.m8
-rw-r--r--test/SemaObjC/warn-write-strings.m4
-rw-r--r--test/SemaObjCXX/objc-pointer-conv.mm12
-rw-r--r--test/SemaTemplate/instantiate-function-1.cpp6
-rw-r--r--test/SemaTemplate/virtual-member-functions.cpp4
-rw-r--r--tools/CIndex/CIndex.cpp35
-rw-r--r--tools/CIndex/CIndex.exports6
-rw-r--r--tools/CIndex/CIndexCodeCompletion.cpp5
-rw-r--r--tools/CIndex/CIndexUSRs.cpp198
-rw-r--r--tools/CIndex/Makefile2
-rw-r--r--tools/Makefile3
-rw-r--r--tools/driver/Makefile2
-rw-r--r--www/analyzer/index.html2
-rw-r--r--www/analyzer/latest_checker.html.incl2
169 files changed, 5621 insertions, 3065 deletions
diff --git a/Makefile b/Makefile
index 8d3fa29a75a4..481dd389aabe 100644
--- a/Makefile
+++ b/Makefile
@@ -39,19 +39,19 @@ cscope.files:
install-local::
$(Echo) Installing include files
- $(Verb) $(MKDIR) $(PROJ_includedir)
+ $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
$(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include" ; then \
cd $(PROJ_SRC_ROOT)/tools/clang/include && \
for hdr in `find . -type f '!' '(' -name '*~' \
-o -name '.#*' -o -name '*.in' -o -name '*.txt' \
-o -name 'Makefile' -o -name '*.td' ')' -print \
| grep -v CVS | grep -v .svn | grep -v .dir` ; do \
- instdir=`dirname "$(PROJ_includedir)/$$hdr"` ; \
+ instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
if test \! -d "$$instdir" ; then \
$(EchoCmd) Making install directory $$instdir ; \
$(MKDIR) $$instdir ;\
fi ; \
- $(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \
+ $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
done ; \
fi
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
@@ -59,7 +59,7 @@ ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
for hdr in `find . -type f '!' '(' -name 'Makefile' ')' -print \
| grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
- $(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \
+ $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
done ; \
fi
endif
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index 1fcc7c8ad493..7bf633532d2a 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -49,6 +49,7 @@
1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVtable.cpp */; };
1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; };
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
+ 1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A96785111486FDC00F24372 /* RecordLayout.cpp */; };
1A97825B1108BA18002B98FC /* CGVTT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A97825A1108BA18002B98FC /* CGVTT.cpp */; };
1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */; };
1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */; };
@@ -420,6 +421,7 @@
1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = "<group>"; tabWidth = 2; };
1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; };
1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; };
+ 1A96785111486FDC00F24372 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayout.cpp; path = lib/AST/RecordLayout.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A97825A1108BA18002B98FC /* CGVTT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTT.cpp; path = lib/CodeGen/CGVTT.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDeclCXX.cpp; path = lib/CodeGen/CGDeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
@@ -1438,6 +1440,7 @@
3557D1A80EB136B100C59739 /* InheritViz.cpp */,
DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */,
35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */,
+ 1A96785111486FDC00F24372 /* RecordLayout.cpp */,
1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */,
1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */,
DE3452400AEF1A2D00DBC861 /* Stmt.cpp */,
@@ -1993,6 +1996,7 @@
1A621C4411111D61009E6834 /* CIndexInclusionStack.cpp in Sources */,
1A621C4511111D61009E6834 /* CIndexUSRs.cpp in Sources */,
1A621C4611111D61009E6834 /* CXCursor.cpp in Sources */,
+ 1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index da186f6424de..15afe8f50376 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -171,7 +171,7 @@ CINDEX_LINKAGE void clang_disposeString(CXString string);
*/
CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
int displayDiagnostics);
-
+
/**
* \brief Destroy the given index.
*
@@ -297,7 +297,7 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu,
* \brief Retrieve a NULL (invalid) source range.
*/
CINDEX_LINKAGE CXSourceRange clang_getNullRange();
-
+
/**
* \brief Retrieve a source range given the beginning and ending source
* locations.
@@ -357,11 +357,11 @@ CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range);
*/
enum CXDiagnosticSeverity {
/**
- * \brief A diagnostic that has been suppressed, e.g., by a command-line
+ * \brief A diagnostic that has been suppressed, e.g., by a command-line
* option.
*/
CXDiagnostic_Ignored = 0,
-
+
/**
* \brief This diagnostic is a note that should be attached to the
* previous (non-note) diagnostic.
@@ -451,7 +451,7 @@ enum CXDiagnosticDisplayOptions {
* diagnostic, also include information about source ranges in a
* machine-parsable format.
*
- * This option corresponds to the clang flag
+ * This option corresponds to the clang flag
* \c -fdiagnostics-print-source-range-info.
*/
CXDiagnostic_DisplaySourceRanges = 0x04
@@ -461,13 +461,13 @@ enum CXDiagnosticDisplayOptions {
* \brief Format the given diagnostic in a manner that is suitable for display.
*
* This routine will format the given diagnostic to a string, rendering
- * the diagnostic according to the various options given. The
- * \c clang_defaultDiagnosticDisplayOptions() function returns the set of
+ * the diagnostic according to the various options given. The
+ * \c clang_defaultDiagnosticDisplayOptions() function returns the set of
* options that most closely mimics the behavior of the clang compiler.
*
* \param Diagnostic The diagnostic to print.
*
- * \param Options A set of options that control the diagnostic display,
+ * \param Options A set of options that control the diagnostic display,
* created by combining \c CXDiagnosticDisplayOptions values.
*
* \returns A new string containing for formatted diagnostic.
@@ -491,7 +491,7 @@ CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void);
/**
* \brief Determine the severity of the given diagnostic.
*/
-CINDEX_LINKAGE enum CXDiagnosticSeverity
+CINDEX_LINKAGE enum CXDiagnosticSeverity
clang_getDiagnosticSeverity(CXDiagnostic);
/**
@@ -512,21 +512,21 @@ CINDEX_LINKAGE CXString clang_getDiagnosticSpelling(CXDiagnostic);
* diagnostic.
*/
CINDEX_LINKAGE unsigned clang_getDiagnosticNumRanges(CXDiagnostic);
-
+
/**
* \brief Retrieve a source range associated with the diagnostic.
*
* A diagnostic's source ranges highlight important elements in the source
* code. On the command line, Clang displays source ranges by
- * underlining them with '~' characters.
+ * underlining them with '~' characters.
*
* \param Diagnostic the diagnostic whose range is being extracted.
*
- * \param Range the zero-based index specifying which range to
+ * \param Range the zero-based index specifying which range to
*
* \returns the requested source range.
*/
-CINDEX_LINKAGE CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic,
+CINDEX_LINKAGE CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic,
unsigned Range);
/**
@@ -560,7 +560,7 @@ CINDEX_LINKAGE unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic);
* \returns A string containing text that should be replace the source
* code indicated by the \c ReplacementRange.
*/
-CINDEX_LINKAGE CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic,
+CINDEX_LINKAGE CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic,
unsigned FixIt,
CXSourceRange *ReplacementRange);
@@ -577,7 +577,7 @@ CINDEX_LINKAGE CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic,
*
* @{
*/
-
+
/**
* \brief Get the original translation unit source file name.
*/
@@ -625,22 +625,22 @@ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile(
const char **clang_command_line_args,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files);
-
+
/**
* \brief Create a translation unit from an AST file (-emit-ast).
*/
-CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex,
+CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex,
const char *ast_filename);
/**
* \brief Destroy the specified CXTranslationUnit object.
*/
CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit);
-
+
/**
* @}
*/
-
+
/**
* \brief Describes the kind of entity that a cursor refers to.
*/
@@ -1083,6 +1083,47 @@ CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent,
CINDEX_LINKAGE CXString clang_getCursorUSR(CXCursor);
/**
+ * \brief Construct a USR for a specified Objective-C class.
+ */
+CINDEX_LINKAGE CXString clang_constructUSR_ObjCClass(const char *class_name);
+
+/**
+ * \brief Construct a USR for a specified Objective-C category.
+ */
+CINDEX_LINKAGE CXString
+ clang_constructUSR_ObjCCategory(const char *class_name,
+ const char *category_name);
+
+/**
+ * \brief Construct a USR for a specified Objective-C protocol.
+ */
+CINDEX_LINKAGE CXString
+ clang_constructUSR_ObjCProtocol(const char *protocol_name);
+
+
+/**
+ * \brief Construct a USR for a specified Objective-C instance variable and
+ * the USR for its containing class.
+ */
+CINDEX_LINKAGE CXString clang_constructUSR_ObjCIvar(const char *name,
+ CXString classUSR);
+
+/**
+ * \brief Construct a USR for a specified Objective-C method and
+ * the USR for its containing class.
+ */
+CINDEX_LINKAGE CXString clang_constructUSR_ObjCMethod(const char *name,
+ unsigned isInstanceMethod,
+ CXString classUSR);
+
+/**
+ * \brief Construct a USR for a specified Objective-C property and the USR
+ * for its containing class.
+ */
+CINDEX_LINKAGE CXString clang_constructUSR_ObjCProperty(const char *property,
+ CXString classUSR);
+
+/**
* \brief Retrieve a name for the entity referenced by this cursor.
*/
CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor);
@@ -1157,22 +1198,22 @@ typedef enum CXTokenKind {
* \brief A token that contains some kind of punctuation.
*/
CXToken_Punctuation,
-
+
/**
* \brief A language keyword.
*/
CXToken_Keyword,
-
+
/**
* \brief An identifier (that is not a keyword).
*/
CXToken_Identifier,
-
+
/**
* \brief A numeric, string, or character literal.
*/
CXToken_Literal,
-
+
/**
* \brief A comment.
*/
@@ -1191,7 +1232,7 @@ typedef struct {
* \brief Determine the kind of the given token.
*/
CINDEX_LINKAGE CXTokenKind clang_getTokenKind(CXToken);
-
+
/**
* \brief Determine the spelling of the given token.
*
@@ -1199,13 +1240,13 @@ CINDEX_LINKAGE CXTokenKind clang_getTokenKind(CXToken);
* the text of an identifier or keyword.
*/
CINDEX_LINKAGE CXString clang_getTokenSpelling(CXTranslationUnit, CXToken);
-
+
/**
* \brief Retrieve the source location of the given token.
*/
-CINDEX_LINKAGE CXSourceLocation clang_getTokenLocation(CXTranslationUnit,
+CINDEX_LINKAGE CXSourceLocation clang_getTokenLocation(CXTranslationUnit,
CXToken);
-
+
/**
* \brief Retrieve a source range that covers the given token.
*/
@@ -1230,7 +1271,7 @@ CINDEX_LINKAGE CXSourceRange clang_getTokenExtent(CXTranslationUnit, CXToken);
*/
CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
CXToken **Tokens, unsigned *NumTokens);
-
+
/**
* \brief Annotate the given set of tokens by providing cursors for each token
* that can be mapped to a specific entity within the abstract syntax tree.
@@ -1264,17 +1305,17 @@ CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
CINDEX_LINKAGE void clang_annotateTokens(CXTranslationUnit TU,
CXToken *Tokens, unsigned NumTokens,
CXCursor *Cursors);
-
+
/**
* \brief Free the given set of tokens.
*/
-CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU,
+CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU,
CXToken *Tokens, unsigned NumTokens);
-
+
/**
* @}
*/
-
+
/**
* \defgroup CINDEX_DEBUG Debugging facilities
*
@@ -1689,7 +1730,7 @@ void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results);
* \brief Determine the number of diagnostics produced prior to the
* location where code completion was performed.
*/
-CINDEX_LINKAGE
+CINDEX_LINKAGE
unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *Results);
/**
@@ -1701,7 +1742,7 @@ unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *Results);
* \returns the requested diagnostic. This diagnostic must be freed
* via a call to \c clang_disposeDiagnostic().
*/
-CINDEX_LINKAGE
+CINDEX_LINKAGE
CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results,
unsigned Index);
@@ -1726,10 +1767,10 @@ CINDEX_LINKAGE CXString clang_getClangVersion();
* \brief Return a version string, suitable for showing to a user, but not
* intended to be parsed (the format is not guaranteed to be stable).
*/
-
-
+
+
/**
- * \brief Visitor invoked for each file in a translation unit
+ * \brief Visitor invoked for each file in a translation unit
* (used with clang_getInclusions()).
*
* This visitor function will be invoked by clang_getInclusions() for each
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index cf9aa50af2a1..d12a182078e4 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -40,6 +40,7 @@ namespace clang {
class ASTRecordLayout;
class BlockExpr;
class CharUnits;
+ class Diagnostic;
class Expr;
class ExternalASTSource;
class IdentifierTable;
@@ -950,8 +951,6 @@ public:
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
void CollectNonClassIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
- void CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI);
unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD);
void CollectInheritedProtocols(const Decl *CDecl,
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index bd9f01b0b5ef..e23811d8f9c0 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -319,7 +319,19 @@ public:
/// \brief Represents a ValueDecl that came out of a declarator.
/// Contains type source information through TypeSourceInfo.
class DeclaratorDecl : public ValueDecl {
- TypeSourceInfo *DeclInfo;
+ // A struct representing both a TInfo and a syntactic qualifier,
+ // to be used for the (uncommon) case of out-of-line declarations.
+ struct ExtInfo {
+ TypeSourceInfo *TInfo;
+ NestedNameSpecifier *NNS;
+ SourceRange NNSRange;
+ };
+
+ llvm::PointerUnion<TypeSourceInfo*, ExtInfo*> DeclInfo;
+
+ bool hasExtInfo() const { return DeclInfo.is<ExtInfo*>(); }
+ ExtInfo *getExtInfo() { return DeclInfo.get<ExtInfo*>(); }
+ const ExtInfo *getExtInfo() const { return DeclInfo.get<ExtInfo*>(); }
protected:
DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L,
@@ -327,8 +339,29 @@ protected:
: ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo) {}
public:
- TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; }
- void setTypeSourceInfo(TypeSourceInfo *TInfo) { DeclInfo = TInfo; }
+ virtual ~DeclaratorDecl();
+ virtual void Destroy(ASTContext &C);
+
+ TypeSourceInfo *getTypeSourceInfo() const {
+ return hasExtInfo()
+ ? DeclInfo.get<ExtInfo*>()->TInfo
+ : DeclInfo.get<TypeSourceInfo*>();
+ }
+ void setTypeSourceInfo(TypeSourceInfo *TI) {
+ if (hasExtInfo())
+ DeclInfo.get<ExtInfo*>()->TInfo = TI;
+ else
+ DeclInfo = TI;
+ }
+
+ NestedNameSpecifier *getQualifier() const {
+ return hasExtInfo() ? DeclInfo.get<ExtInfo*>()->NNS : 0;
+ }
+ SourceRange getQualifierRange() const {
+ return hasExtInfo() ? DeclInfo.get<ExtInfo*>()->NNSRange : SourceRange();
+ }
+ void setQualifierInfo(NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange);
SourceLocation getTypeSpecStartLoc() const;
@@ -500,7 +533,8 @@ public:
bool isExternC() const;
/// isBlockVarDecl - Returns true for local variable declarations. Note that
- /// this includes static variables inside of functions.
+ /// this includes static variables inside of functions. It also includes
+ /// variables inside blocks.
///
/// void foo() { int x; static int y; extern int z; }
///
@@ -512,6 +546,17 @@ public:
return false;
}
+ /// isFunctionOrMethodVarDecl - Similar to isBlockVarDecl, but excludes
+ /// variables declared in blocks.
+ bool isFunctionOrMethodVarDecl() const {
+ if (getKind() != Decl::Var)
+ return false;
+ if (const DeclContext *DC = getDeclContext())
+ return DC->getLookupContext()->isFunctionOrMethod() &&
+ DC->getLookupContext()->getDeclKind() != Decl::Block;
+ return false;
+ }
+
/// \brief Determines whether this is a static data member.
///
/// This will only be true in C++, and applies to, e.g., the
@@ -797,12 +842,14 @@ class ParmVarDecl : public VarDecl {
/// FIXME: Also can be paced into the bitfields in Decl.
/// in, inout, etc.
unsigned objcDeclQualifier : 6;
+ bool HasInheritedDefaultArg : 1;
protected:
ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass S, Expr *DefArg)
- : VarDecl(DK, DC, L, Id, T, TInfo, S), objcDeclQualifier(OBJC_TQ_None) {
+ : VarDecl(DK, DC, L, Id, T, TInfo, S),
+ objcDeclQualifier(OBJC_TQ_None), HasInheritedDefaultArg(false) {
setDefaultArg(DefArg);
}
@@ -881,6 +928,14 @@ public:
Init = (UnparsedDefaultArgument *)0;
}
+ bool hasInheritedDefaultArg() const {
+ return HasInheritedDefaultArg;
+ }
+
+ void setHasInheritedDefaultArg(bool I = true) {
+ HasInheritedDefaultArg = I;
+ }
+
QualType getOriginalType() const {
if (getTypeSourceInfo())
return getTypeSourceInfo()->getType();
@@ -1512,22 +1567,38 @@ private:
/// IsEmbeddedInDeclarator - True if this tag declaration is
/// "embedded" (i.e., defined or declared for the very first time)
- /// in the syntax of a declarator,
+ /// in the syntax of a declarator.
bool IsEmbeddedInDeclarator : 1;
- /// TypedefForAnonDecl - If a TagDecl is anonymous and part of a typedef,
- /// this points to the TypedefDecl. Used for mangling.
- TypedefDecl *TypedefForAnonDecl;
-
SourceLocation TagKeywordLoc;
SourceLocation RBraceLoc;
+ // A struct representing syntactic qualifier info,
+ // to be used for the (uncommon) case of out-of-line declarations.
+ struct ExtInfo {
+ NestedNameSpecifier *NNS;
+ SourceRange NNSRange;
+ };
+
+ /// TypedefDeclOrQualifier - If the (out-of-line) tag declaration name
+ /// is qualified, it points to the qualifier info (nns and range);
+ /// otherwise, if the tag declaration is anonymous and it is part of
+ /// a typedef, it points to the TypedefDecl (used for mangling);
+ /// otherwise, it is a null (TypedefDecl) pointer.
+ llvm::PointerUnion<TypedefDecl*, ExtInfo*> TypedefDeclOrQualifier;
+
+ bool hasExtInfo() const { return TypedefDeclOrQualifier.is<ExtInfo*>(); }
+ ExtInfo *getExtInfo() { return TypedefDeclOrQualifier.get<ExtInfo*>(); }
+ const ExtInfo *getExtInfo() const {
+ return TypedefDeclOrQualifier.get<ExtInfo*>();
+ }
+
protected:
- TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, TagDecl *PrevDecl,
- SourceLocation TKL = SourceLocation())
- : TypeDecl(DK, DC, L, Id), DeclContext(DK), TypedefForAnonDecl(0),
- TagKeywordLoc(TKL) {
+ TagDecl(Kind DK, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ TagDecl *PrevDecl, SourceLocation TKL = SourceLocation())
+ : TypeDecl(DK, DC, L, Id), DeclContext(DK), TagKeywordLoc(TKL),
+ TypedefDeclOrQualifier((TypedefDecl*) 0) {
assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum");
TagDeclKind = TK;
IsDefinition = false;
@@ -1539,6 +1610,8 @@ protected:
virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
public:
+ void Destroy(ASTContext &C);
+
typedef redeclarable_base::redecl_iterator redecl_iterator;
redecl_iterator redecls_begin() const {
return redeclarable_base::redecls_begin();
@@ -1618,8 +1691,21 @@ public:
bool isUnion() const { return getTagKind() == TK_union; }
bool isEnum() const { return getTagKind() == TK_enum; }
- TypedefDecl *getTypedefForAnonDecl() const { return TypedefForAnonDecl; }
- void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefForAnonDecl = TDD; }
+ TypedefDecl *getTypedefForAnonDecl() const {
+ return hasExtInfo() ? 0 : TypedefDeclOrQualifier.get<TypedefDecl*>();
+ }
+ void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefDeclOrQualifier = TDD; }
+
+ NestedNameSpecifier *getQualifier() const {
+ return hasExtInfo() ? TypedefDeclOrQualifier.get<ExtInfo*>()->NNS : 0;
+ }
+ SourceRange getQualifierRange() const {
+ return hasExtInfo()
+ ? TypedefDeclOrQualifier.get<ExtInfo*>()->NNSRange
+ : SourceRange();
+ }
+ void setQualifierInfo(NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 0bdc6f54b7ca..6f8284458f2b 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -660,7 +660,7 @@ public:
/// \brief Determine whether this declaration context is equivalent
/// to the declaration context DC.
bool Equals(DeclContext *DC) {
- return this->getPrimaryContext() == DC->getPrimaryContext();
+ return DC && this->getPrimaryContext() == DC->getPrimaryContext();
}
/// \brief Determine whether this declaration context encloses the
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index af00c8d7e8ad..6b04ed54109a 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -7,7 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the C++ Decl subclasses.
+// This file defines the C++ Decl subclasses, other than those for
+// templates (in DeclTemplate.h) and friends (in DeclFriend.h).
//
//===----------------------------------------------------------------------===//
@@ -32,6 +33,7 @@ class CXXDestructorDecl;
class CXXMethodDecl;
class CXXRecordDecl;
class CXXMemberLookupCriteria;
+class FriendDecl;
/// \brief Represents any kind of function declaration, whether it is a
/// concrete function or a function template.
@@ -298,6 +300,11 @@ class CXXRecordDecl : public RecordDecl {
/// Definition - The declaration which defines this record.
CXXRecordDecl *Definition;
+ /// FirstFriend - The first friend declaration in this class, or
+ /// null if there aren't any. This is actually currently stored
+ /// in reverse order.
+ FriendDecl *FirstFriend;
+
} *DefinitionData;
struct DefinitionData &data() {
@@ -322,12 +329,6 @@ class CXXRecordDecl : public RecordDecl {
llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
TemplateOrInstantiation;
- void getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
- const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet,
- const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes);
- void collectConversionFunctions(
- llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const;
-
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
@@ -458,6 +459,13 @@ public:
return ctor_iterator(decls_end());
}
+ /// An iterator over friend declarations. All of these are defined
+ /// in DeclFriend.h.
+ class friend_iterator;
+ friend_iterator friend_begin() const;
+ friend_iterator friend_end() const;
+ void pushFriendDecl(FriendDecl *FD);
+
/// hasConstCopyConstructor - Determines whether this class has a
/// copy constructor that accepts a const-qualified argument.
bool hasConstCopyConstructor(ASTContext &Context) const;
@@ -545,14 +553,6 @@ public:
/// in current class; including conversion function templates.
const UnresolvedSetImpl *getVisibleConversionFunctions();
- /// addVisibleConversionFunction - Add a new conversion function to the
- /// list of visible conversion functions.
- void addVisibleConversionFunction(CXXConversionDecl *ConvDecl);
-
- /// \brief Add a new conversion function template to the list of visible
- /// conversion functions.
- void addVisibleConversionFunction(FunctionTemplateDecl *ConvDecl);
-
/// addConversionFunction - Add a new conversion function to the
/// list of conversion functions.
void addConversionFunction(CXXConversionDecl *ConvDecl);
@@ -1385,77 +1385,6 @@ public:
static bool classofKind(Kind K) { return K == CXXConversion; }
};
-/// FriendDecl - Represents the declaration of a friend entity,
-/// which can be a function, a type, or a templated function or type.
-// For example:
-///
-/// @code
-/// template <typename T> class A {
-/// friend int foo(T);
-/// friend class B;
-/// friend T; // only in C++0x
-/// template <typename U> friend class C;
-/// template <typename U> friend A& operator+=(A&, const U&) { ... }
-/// };
-/// @endcode
-///
-/// The semantic context of a friend decl is its declaring class.
-class FriendDecl : public Decl {
-public:
- typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
-
-private:
- // The declaration that's a friend of this class.
- FriendUnion Friend;
-
- // Location of the 'friend' specifier.
- SourceLocation FriendLoc;
-
- // FIXME: Hack to keep track of whether this was a friend function
- // template specialization.
- bool WasSpecialization;
-
- FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
- SourceLocation FriendL)
- : Decl(Decl::Friend, DC, L),
- Friend(Friend),
- FriendLoc(FriendL),
- WasSpecialization(false) {
- }
-
-public:
- static FriendDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, FriendUnion Friend_,
- SourceLocation FriendL);
-
- /// If this friend declaration names an (untemplated but
- /// possibly dependent) type, return the type; otherwise
- /// return null. This is used only for C++0x's unelaborated
- /// friend type declarations.
- Type *getFriendType() const {
- return Friend.dyn_cast<Type*>();
- }
-
- /// If this friend declaration doesn't name an unelaborated
- /// type, return the inner declaration.
- NamedDecl *getFriendDecl() const {
- return Friend.dyn_cast<NamedDecl*>();
- }
-
- /// Retrieves the location of the 'friend' keyword.
- SourceLocation getFriendLoc() const {
- return FriendLoc;
- }
-
- bool wasSpecialization() const { return WasSpecialization; }
- void setSpecialization(bool WS) { WasSpecialization = WS; }
-
- // Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const FriendDecl *D) { return true; }
- static bool classofKind(Kind K) { return K == Decl::Friend; }
-};
-
/// LinkageSpecDecl - This represents a linkage specification. For example:
/// extern "C" void foo();
///
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
new file mode 100644
index 000000000000..5022ad018f4f
--- /dev/null
+++ b/include/clang/AST/DeclFriend.h
@@ -0,0 +1,167 @@
+//===-- DeclFriend.h - Classes for C++ friend declarations -*- C++ -*------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the section of the AST representing C++ friend
+// declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECLFRIEND_H
+#define LLVM_CLANG_AST_DECLFRIEND_H
+
+#include "clang/AST/DeclCXX.h"
+
+namespace clang {
+
+/// FriendDecl - Represents the declaration of a friend entity,
+/// which can be a function, a type, or a templated function or type.
+// For example:
+///
+/// @code
+/// template <typename T> class A {
+/// friend int foo(T);
+/// friend class B;
+/// friend T; // only in C++0x
+/// template <typename U> friend class C;
+/// template <typename U> friend A& operator+=(A&, const U&) { ... }
+/// };
+/// @endcode
+///
+/// The semantic context of a friend decl is its declaring class.
+class FriendDecl : public Decl {
+public:
+ typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
+
+private:
+ // The declaration that's a friend of this class.
+ FriendUnion Friend;
+
+ // A pointer to the next friend in the sequence.
+ FriendDecl *NextFriend;
+
+ // Location of the 'friend' specifier.
+ SourceLocation FriendLoc;
+
+ // FIXME: Hack to keep track of whether this was a friend function
+ // template specialization.
+ bool WasSpecialization;
+
+ friend class CXXRecordDecl::friend_iterator;
+ friend class CXXRecordDecl;
+
+ FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
+ SourceLocation FriendL)
+ : Decl(Decl::Friend, DC, L),
+ Friend(Friend),
+ NextFriend(0),
+ FriendLoc(FriendL),
+ WasSpecialization(false) {
+ }
+
+public:
+ static FriendDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, FriendUnion Friend_,
+ SourceLocation FriendL);
+
+ /// If this friend declaration names an (untemplated but
+ /// possibly dependent) type, return the type; otherwise
+ /// return null. This is used only for C++0x's unelaborated
+ /// friend type declarations.
+ Type *getFriendType() const {
+ return Friend.dyn_cast<Type*>();
+ }
+
+ /// If this friend declaration doesn't name an unelaborated
+ /// type, return the inner declaration.
+ NamedDecl *getFriendDecl() const {
+ return Friend.dyn_cast<NamedDecl*>();
+ }
+
+ /// Retrieves the location of the 'friend' keyword.
+ SourceLocation getFriendLoc() const {
+ return FriendLoc;
+ }
+
+ bool wasSpecialization() const { return WasSpecialization; }
+ void setSpecialization(bool WS) { WasSpecialization = WS; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classof(const FriendDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Decl::Friend; }
+};
+
+/// An iterator over the friend declarations of a class.
+class CXXRecordDecl::friend_iterator {
+ FriendDecl *Ptr;
+
+ friend class CXXRecordDecl;
+ explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {}
+public:
+ friend_iterator() {}
+
+ typedef FriendDecl *value_type;
+ typedef FriendDecl *reference;
+ typedef FriendDecl *pointer;
+ typedef int difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ reference operator*() const { return Ptr; }
+
+ friend_iterator &operator++() {
+ assert(Ptr && "attempt to increment past end of friend list");
+ Ptr = Ptr->NextFriend;
+ return *this;
+ }
+
+ friend_iterator operator++(int) {
+ friend_iterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ bool operator==(const friend_iterator &Other) const {
+ return Ptr == Other.Ptr;
+ }
+
+ bool operator!=(const friend_iterator &Other) const {
+ return Ptr != Other.Ptr;
+ }
+
+ friend_iterator &operator+=(difference_type N) {
+ assert(N >= 0 && "cannot rewind a CXXRecordDecl::friend_iterator");
+ while (N--)
+ ++*this;
+ return *this;
+ }
+
+ friend_iterator operator+(difference_type N) const {
+ friend_iterator tmp = *this;
+ tmp += N;
+ return tmp;
+ }
+};
+
+inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
+ return friend_iterator(data().FirstFriend);
+}
+
+inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
+ return friend_iterator(0);
+}
+
+inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
+ assert(FD->NextFriend == 0 && "friend already has next friend?");
+ FD->NextFriend = data().FirstFriend;
+ data().FirstFriend = FD;
+}
+
+}
+
+#endif
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 889e0d6c1be8..a1f565341e2c 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -381,8 +381,6 @@ public:
ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const;
ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const;
- ObjCPropertyDecl *FindPropertyVisibleInPrimaryClass(
- IdentifierInfo *PropertyId) const;
// Marks the end of the container.
SourceRange getAtEndRange() const {
@@ -445,9 +443,6 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
/// Protocols referenced in interface header declaration
ObjCProtocolList ReferencedProtocols;
- /// Instance variables in the interface. This list is completely redundant.
- ObjCList<ObjCIvarDecl> IVars;
-
/// List of categories defined for this class.
/// FIXME: Why is this a linked list??
ObjCCategoryDecl *CategoryList;
@@ -538,7 +533,10 @@ public:
}
ObjCCategoryDecl* getClassExtension() const;
-
+
+ ObjCPropertyDecl
+ *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const;
+
/// isSuperClassOf - Return true if this class is the specified class or is a
/// super class of the specified interface class.
bool isSuperClassOf(const ObjCInterfaceDecl *I) const {
@@ -1330,6 +1328,10 @@ public:
return PropertyIvarDecl;
}
+ /// Lookup a property by name in the specified DeclContext.
+ static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC,
+ IdentifierInfo *propertyID);
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCPropertyDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCProperty; }
diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h
index 9423c319c3e3..140e5c0a2a99 100644
--- a/include/clang/AST/DeclVisitor.h
+++ b/include/clang/AST/DeclVisitor.h
@@ -16,6 +16,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
namespace clang {
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index cd25969db0b0..e78476ef51bb 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -112,13 +112,14 @@ private:
/// PrimaryBase - The primary base info for this record.
PrimaryBaseInfo PrimaryBase;
- /// BaseOffsets - Contains a map from base classes to their offset.
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsets;
+ typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy;
+
+ /// BaseOffsets - Contains a map from base classes to their offset.
+ BaseOffsetsMapTy BaseOffsets;
/// VBaseOffsets - Contains a map from vbase classes to their offset.
- /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> VBaseOffsets;
+ BaseOffsetsMapTy VBaseOffsets;
};
/// CXXInfo - If the record layout is for a C++ record, this will have
@@ -133,15 +134,14 @@ private:
unsigned fieldcount);
// Constructor for C++ records.
+ typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
ASTRecordLayout(ASTContext &Ctx,
uint64_t size, unsigned alignment, uint64_t datasize,
const uint64_t *fieldoffsets, unsigned fieldcount,
uint64_t nonvirtualsize, unsigned nonvirtualalign,
const PrimaryBaseInfo &PrimaryBase,
- const std::pair<const CXXRecordDecl *, uint64_t> *bases,
- unsigned numbases,
- const std::pair<const CXXRecordDecl *, uint64_t> *vbases,
- unsigned numvbases);
+ const BaseOffsetsMapTy& BaseOffsets,
+ const BaseOffsetsMapTy& VBaseOffsets);
~ASTRecordLayout() {}
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 528cf878031e..b7256c9dc3db 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -286,7 +286,8 @@ public:
/// constructed CFG belongs to the caller.
static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C,
bool AddEHEdges = false,
- bool AddScopes = false);
+ bool AddScopes = false /* NOT FULLY IMPLEMENTED.
+ NOT READY FOR GENERAL USE. */);
/// createBlock - Create a new block in the CFG. The CFG owns the block;
/// the caller should not directly free it.
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index af233b81e0a5..3afdaf5b0eb1 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -46,8 +46,8 @@
// U -> unsigned
//
// Types may be postfixed with the following modifiers:
-// * -> pointer
-// & -> reference
+// * -> pointer (optionally followed by an address space number)
+// & -> reference (optionally followed by an address space number)
// C -> const
// D -> volatile
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 880b4bab6e26..9a79f90d1e52 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -287,6 +287,10 @@ BUILTIN(__builtin_ia32_roundpd, "V2dV2di", "")
BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fi", "")
BUILTIN(__builtin_ia32_dppd, "V2dV2dV2di", "")
BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLi*", "")
-
+BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_pcmpeqq, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16ci", "")
#undef BUILTIN
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 66f84dbbbabe..849e6437fbe6 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -63,4 +63,12 @@ def err_target_unknown_cpu : Error<"unknown target CPU '%0'">;
def err_target_unknown_abi : Error<"unknown target ABI '%0'">;
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/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 17bad64e9c82..e5793fa58b04 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -59,7 +59,7 @@ def : DiagGroup<"nested-externs">;
def : DiagGroup<"newline-eof">;
def LongLong : DiagGroup<"long-long">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
-def : DiagGroup<"missing-field-initializers">;
+def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
def NonNull : DiagGroup<"nonnull">;
def : DiagGroup<"nonportable-cfstrings">;
def : DiagGroup<"non-virtual-dtor">;
@@ -147,6 +147,7 @@ def Format2 : DiagGroup<"format=2",
[FormatNonLiteral, FormatSecurity, FormatY2K]>;
def Extra : DiagGroup<"extra", [
+ MissingFieldInitializers,
SemiBeforeMethodBody,
SignCompare,
UnusedParameter
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 80a4eaee1120..9d001d48cc2a 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -183,6 +183,7 @@ def err_objc_no_attributes_on_category : Error<
def err_objc_missing_end : Error<"missing @end">;
def warn_objc_protocol_qualifier_missing_id : Warning<
"protocol qualifiers without 'id' is archaic">;
+def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">;
def err_objc_illegal_visibility_spec : Error<
"illegal visibility specification">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 13ac9ece542b..9a9b7cc85f6a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -428,11 +428,39 @@ def err_deep_exception_specs_differ : Error<
// C++ access checking
def err_class_redeclared_with_different_access : Error<
"%0 redeclared with '%1' access">;
-def err_access_private : Error<"%0 is a private member of %1">;
-def err_access_ctor_private : Error<"calling a private constructor of %0">;
-// Say something about the context for these?
-def err_access_protected : Error<"%0 is a protected member of %1">;
-def err_access_ctor_protected : Error<"calling a protected constructor of %0">;
+def err_access :
+ Error<"%1 is a %select{private|protected}0 member of %3">,
+ NoSFINAE;
+def err_access_ctor :
+ Error<"calling a %select{private|protected}0 constructor of class %2">,
+ NoSFINAE;
+def err_access_dtor_base :
+ Error<"base class %0 has %select{private|protected}1 destructor">,
+ NoSFINAE;
+def err_access_dtor_vbase :
+ Error<"inherited virtual base class %0 has "
+ "%select{private|protected}1 destructor">,
+ NoSFINAE;
+def err_access_dtor_field :
+ Error<"field of type %1 has %select{private|protected}2 destructor">,
+ NoSFINAE;
+def err_access_dtor_var :
+ Error<"variable of type %1 has %select{private|protected}2 destructor">,
+ NoSFINAE;
+def err_access_assign_field :
+ Error<"field of type %1 has %select{private|protected}2 copy assignment"
+ " operator">,
+ NoSFINAE;
+def err_access_assign_base :
+ Error<"base class %0 has %select{private|protected}1 copy assignment"
+ " operator">,
+ NoSFINAE;
+def err_access_copy_field :
+ Error<"field of type %1 has %select{private|protected}2 copy constructor">,
+ NoSFINAE;
+def err_access_copy_base :
+ Error<"base class %0 has %select{private|protected}1 copy constructor">,
+ NoSFINAE;
def note_previous_access_declaration : Note<
"previously declared '%1' here">;
def err_access_outside_class : Error<
@@ -1251,7 +1279,7 @@ def err_not_class_template_specialization : Error<
def err_template_spec_needs_header : Error<
"template specialization requires 'template<>'">;
def err_template_spec_needs_template_parameters : Error<
- "template specialization or definition requires a template parameter list"
+ "template specialization or definition requires a template parameter list "
"corresponding to the nested type %0">;
def err_template_param_list_matches_nontemplate : Error<
"template parameter list matching the non-templated nested type %0 should "
@@ -1562,6 +1590,9 @@ def warn_excess_initializers_in_char_array_initializer : ExtWarn<
"excess elements in char array initializer">;
def warn_initializer_string_for_char_array_too_long : ExtWarn<
"initializer-string for char array is too long">;
+def warn_missing_field_initializers : Warning<
+ "missing field '%0' initializer">,
+ InGroup<MissingFieldInitializers>, DefaultIgnore;
def warn_braces_around_scalar_init : Warning<
"braces around scalar initializer">;
def err_many_braces_around_scalar_init : Error<
@@ -1854,6 +1885,12 @@ def warn_mixed_sign_comparison : Warning<
def warn_mixed_sign_conditional : Warning<
"operands of ? are integers of different signs: %0 and %1">,
InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
+def warn_lunsigned_always_true_comparison : Warning<
+ "comparison of unsigned expression %0 is always %1">,
+ InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
+def warn_runsigned_always_true_comparison : Warning<
+ "comparison of %0 unsigned expression is always %1">,
+ InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
def err_invalid_this_use : Error<
"invalid use of 'this' outside of a nonstatic member function">;
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 75a7b8192c5a..582d59c18a37 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -18,6 +18,7 @@
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
@@ -236,9 +237,7 @@ public:
/// Unlike the version in IdentifierTable, this returns a pointer instead
/// of a reference. If the pointer is NULL then the IdentifierInfo cannot
/// be found.
- //
- // FIXME: Move to StringRef API.
- virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd) = 0;
+ virtual IdentifierInfo* get(llvm::StringRef Name) = 0;
};
/// \brief An abstract class used to resolve numerical identifier
@@ -283,16 +282,16 @@ public:
/// get - Return the identifier token info for the specified named identifier.
///
- IdentifierInfo &get(const char *NameStart, const char *NameEnd) {
+ IdentifierInfo &get(llvm::StringRef Name) {
llvm::StringMapEntry<IdentifierInfo*> &Entry =
- HashTable.GetOrCreateValue(NameStart, NameEnd);
+ HashTable.GetOrCreateValue(Name);
IdentifierInfo *II = Entry.getValue();
if (II) return *II;
// No entry; if we have an external lookup, look there first.
if (ExternalLookup) {
- II = ExternalLookup->get(NameStart, NameEnd);
+ II = ExternalLookup->get(Name);
if (II) {
// Cache in the StringMap for subsequent lookups.
Entry.setValue(II);
@@ -312,6 +311,14 @@ public:
return *II;
}
+ IdentifierInfo &get(const char *NameStart, const char *NameEnd) {
+ return get(llvm::StringRef(NameStart, NameEnd-NameStart));
+ }
+
+ IdentifierInfo &get(const char *Name, size_t NameLen) {
+ return get(llvm::StringRef(Name, NameLen));
+ }
+
/// \brief Creates a new IdentifierInfo from the given string.
///
/// This is a lower-level version of get() that requires that this
@@ -343,10 +350,6 @@ public:
return CreateIdentifierInfo(Name.begin(), Name.end());
}
- IdentifierInfo &get(llvm::StringRef Name) {
- return get(Name.begin(), Name.end());
- }
-
typedef HashTableTy::const_iterator iterator;
typedef HashTableTy::const_iterator const_iterator;
@@ -474,9 +477,7 @@ public:
SelectorName = "set";
SelectorName += Name->getName();
SelectorName[3] = toupper(SelectorName[3]);
- IdentifierInfo *SetterName =
- &Idents.get(SelectorName.data(),
- SelectorName.data() + SelectorName.size());
+ IdentifierInfo *SetterName = &Idents.get(SelectorName);
return SelTable.getUnarySelector(SetterName);
}
};
@@ -533,7 +534,7 @@ struct DenseMapInfo<clang::Selector> {
return LHS == RHS;
}
};
-
+
template <>
struct isPodLike<clang::Selector> { static const bool value = true; };
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 23e6efe8bd70..fdf69d063f4d 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -44,6 +44,7 @@ public:
unsigned PascalStrings : 1; // Allow Pascal strings
unsigned WritableStrings : 1; // Allow writable strings
+ unsigned ConstStrings : 1; // Add const qualifier to strings (-Wwrite-strings)
unsigned LaxVectorConversions : 1;
unsigned AltiVec : 1; // Support AltiVec-style vector initializers.
unsigned Exceptions : 1; // Support exception handling.
@@ -129,7 +130,7 @@ public:
HexFloats = 0;
GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0;
C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0;
- CXXOperatorNames = PascalStrings = WritableStrings = 0;
+ CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0;
Exceptions = SjLjExceptions = Freestanding = NoBuiltin = 0;
NeXTRuntime = 1;
RTTI = 1;
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index 873aaeecb6bf..fb861dcf934d 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -69,6 +69,10 @@ class PartialDiagnostic {
CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
};
+ // NOTE: Sema assumes that PartialDiagnostic is location-invariant
+ // in the sense that its bits can be safely memcpy'ed and destructed
+ // in the new location.
+
/// DiagID - The diagnostic ID.
mutable unsigned DiagID;
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index d4f557b57d0b..34dfecd9b6a8 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -20,6 +20,7 @@
namespace llvm {
class MemoryBuffer;
class raw_ostream;
+ class StringRef;
template <typename T> struct DenseMapInfo;
template <typename T> struct isPodLike;
}
@@ -209,9 +210,9 @@ public:
const llvm::MemoryBuffer* getBuffer() const;
- /// getBufferData - Return a pointer to the start and end of the source buffer
- /// data for the specified FileID.
- std::pair<const char*, const char*> getBufferData() const;
+ /// getBufferData - Return a StringRef to the source buffer data for the
+ /// specified FileID.
+ llvm::StringRef getBufferData() 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 15ece685104c..ef51a5888379 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -17,22 +17,24 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/Allocator.h"
#include "llvm/System/DataTypes.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/DenseMap.h"
#include <vector>
#include <cassert>
namespace llvm {
class MemoryBuffer;
+class StringRef;
}
namespace clang {
+class Diagnostic;
class SourceManager;
class FileManager;
class FileEntry;
-class IdentifierTokenInfo;
class LineTableInfo;
-
+
/// SrcMgr - Public enums and private classes that are part of the
/// SourceManager implementation.
///
@@ -69,10 +71,14 @@ namespace SrcMgr {
/// if SourceLineCache is non-null.
unsigned NumLines;
- /// getBuffer - Returns the memory buffer for the associated content. If
- /// there is an error opening this buffer the first time, this manufactures
- /// a temporary buffer and returns a non-empty error string.
- const llvm::MemoryBuffer *getBuffer(std::string *ErrorStr = 0) const;
+ /// getBuffer - Returns the memory buffer for the associated content.
+ ///
+ /// \param Diag Object through which diagnostics will be emitted it the
+ /// buffer cannot be retrieved.
+ ///
+ /// \param Invalid If non-NULL, will be set \c true if an error occurred.
+ const llvm::MemoryBuffer *getBuffer(Diagnostic &Diag,
+ bool *Invalid = 0) const;
/// getSize - Returns the size of the content encapsulated by this
/// ContentCache. This can be the size of the source file or the size of an
@@ -277,6 +283,9 @@ public:
/// location indicates where the expanded token came from and the instantiation
/// location specifies where it was expanded.
class SourceManager {
+ /// \brief Diagnostic object.
+ Diagnostic &Diag;
+
mutable llvm::BumpPtrAllocator ContentCacheAlloc;
/// FileInfos - Memoized information about all of the files tracked by this
@@ -336,8 +345,8 @@ class SourceManager {
explicit SourceManager(const SourceManager&);
void operator=(const SourceManager&);
public:
- SourceManager()
- : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
+ SourceManager(Diagnostic &Diag)
+ : Diag(Diag), ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
NumBinaryProbes(0) {
clearIDTables();
}
@@ -408,7 +417,11 @@ public:
unsigned Offset = 0);
/// \brief Retrieve the memory buffer associated with the given file.
- const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File);
+ ///
+ /// \param Invalid If non-NULL, will be set \c true if an error
+ /// occurs while retrieving the memory buffer.
+ const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File,
+ bool *Invalid = 0);
/// \brief Override the contents of the given source file by providing an
/// already-allocated buffer.
@@ -429,8 +442,9 @@ public:
/// getBuffer - Return the buffer for the specified FileID. If there is an
/// error opening this buffer the first time, this manufactures a temporary
/// buffer and returns a non-empty error string.
- const llvm::MemoryBuffer *getBuffer(FileID FID, std::string *Error = 0) const{
- return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Error);
+ const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const {
+ return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Diag,
+ Invalid);
}
/// getFileEntryForID - Returns the FileEntry record for the provided FileID.
@@ -438,9 +452,12 @@ public:
return getSLocEntry(FID).getFile().getContentCache()->Entry;
}
- /// getBufferData - Return a pointer to the start and end of the source buffer
- /// data for the specified FileID.
- std::pair<const char*, const char*> getBufferData(FileID FID) const;
+ /// getBufferData - Return a StringRef to the source buffer data for the
+ /// specified FileID.
+ ///
+ /// \param FID The file ID whose contents will be returned.
+ /// \param Invalid If non-NULL, will be set true if an error occurred.
+ llvm::StringRef getBufferData(FileID FID, bool *Invalid = 0) const;
//===--------------------------------------------------------------------===//
@@ -558,31 +575,37 @@ public:
/// getCharacterData - Return a pointer to the start of the specified location
/// in the appropriate spelling MemoryBuffer.
- const char *getCharacterData(SourceLocation SL) const;
+ ///
+ /// \param Invalid If non-NULL, will be set \c true if an error occurs.
+ const char *getCharacterData(SourceLocation SL, bool *Invalid = 0) const;
/// getColumnNumber - Return the column # for the specified file position.
/// This is significantly cheaper to compute than the line number. This
/// returns zero if the column number isn't known. This may only be called on
/// a file sloc, so you must choose a spelling or instantiation location
/// before calling this method.
- unsigned getColumnNumber(FileID FID, unsigned FilePos) const;
- unsigned getSpellingColumnNumber(SourceLocation Loc) const;
- unsigned getInstantiationColumnNumber(SourceLocation Loc) const;
+ unsigned getColumnNumber(FileID FID, unsigned FilePos,
+ bool *Invalid = 0) const;
+ unsigned getSpellingColumnNumber(SourceLocation Loc,
+ bool *Invalid = 0) const;
+ unsigned getInstantiationColumnNumber(SourceLocation Loc,
+ bool *Invalid = 0) const;
/// getLineNumber - Given a SourceLocation, return the spelling line number
/// for the position indicated. This requires building and caching a table of
/// line offsets for the MemoryBuffer, so this is not cheap: use only when
/// about to emit a diagnostic.
- unsigned getLineNumber(FileID FID, unsigned FilePos) const;
+ unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid = 0) const;
- unsigned getInstantiationLineNumber(SourceLocation Loc) const;
- unsigned getSpellingLineNumber(SourceLocation Loc) const;
+ unsigned getInstantiationLineNumber(SourceLocation Loc,
+ bool *Invalid = 0) const;
+ unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid = 0) const;
/// Return the filename or buffer identifier of the buffer the location is in.
/// Note that this name does not respect #line directives. Use getPresumedLoc
/// for normal clients.
- const char *getBufferName(SourceLocation Loc) const;
+ const char *getBufferName(SourceLocation Loc, bool *Invalid = 0) const;
/// getFileCharacteristic - return the file characteristic of the specified
/// source location, indicating whether this is a normal file, a system
@@ -678,7 +701,7 @@ public:
void PrintStats() const;
unsigned sloc_entry_size() const { return SLocEntryTable.size(); }
-
+
// FIXME: Exposing this is a little gross; what we want is a good way
// to iterate the entries that were not defined in a PCH file (or
// any other external source).
@@ -692,8 +715,8 @@ public:
ExternalSLocEntries->ReadSLocEntry(ID);
return SLocEntryTable[ID];
}
-
- const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const {
+
+ const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const {
return getSLocEntry(FID.ID);
}
diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h
index 763bbcc9e1da..916511e8bd09 100644
--- a/include/clang/Checker/PathSensitive/GRExprEngine.h
+++ b/include/clang/Checker/PathSensitive/GRExprEngine.h
@@ -347,7 +347,10 @@ protected:
void VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst);
-
+
+ void VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// Create a C++ temporary object for an rvalue.
void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index 679704c39587..ab3162a04707 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -66,17 +66,23 @@ private:
ActionList Inputs;
+ unsigned OwnsInputs : 1;
+
protected:
- Action(ActionClass _Kind, types::ID _Type) : Kind(_Kind), Type(_Type) {}
+ Action(ActionClass _Kind, types::ID _Type)
+ : Kind(_Kind), Type(_Type), OwnsInputs(true) {}
Action(ActionClass _Kind, Action *Input, types::ID _Type)
- : Kind(_Kind), Type(_Type), Inputs(&Input, &Input + 1) {}
+ : Kind(_Kind), Type(_Type), Inputs(&Input, &Input + 1), OwnsInputs(true) {}
Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type)
- : Kind(_Kind), Type(_Type), Inputs(_Inputs) {}
+ : Kind(_Kind), Type(_Type), Inputs(_Inputs), OwnsInputs(true) {}
public:
virtual ~Action();
const char *getClassName() const { return Action::getClassName(getKind()); }
+ bool getOwnsInputs() { return OwnsInputs; }
+ void setOwnsInputs(bool Value) { OwnsInputs = Value; }
+
ActionClass getKind() const { return Kind; }
types::ID getType() const { return Type; }
diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h
index ab1abff7409b..0a8eaeaf238f 100644
--- a/include/clang/Driver/ArgList.h
+++ b/include/clang/Driver/ArgList.h
@@ -287,7 +287,7 @@ namespace driver {
arglist_type ActualArgs;
/// The list of arguments we synthesized.
- arglist_type SynthesizedArgs;
+ mutable arglist_type SynthesizedArgs;
/// Is this only a proxy for the base ArgList?
bool OnlyProxy;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 7cd26ef04cc2..1ecd8d6adaf6 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -197,6 +197,8 @@ def fcolor_diagnostics : Flag<"-fcolor-diagnostics">,
HelpText<"Use colors in diagnostics">;
def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">,
HelpText<"Silence ObjC rewriting warnings">;
+def Wwrite_strings : Flag<"-Wwrite-strings">,
+ HelpText<"Add const qualifier to string literals">;
def verify : Flag<"-verify">,
HelpText<"Verify emitted diagnostics and warnings">;
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index 74ca083417a6..5a789fbb8f41 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -100,7 +100,9 @@ private:
public:
PipedJob();
+ virtual ~PipedJob();
+ /// Add a command to the piped job (taking ownership).
void addCommand(Command *C) { Commands.push_back(C); }
const list_type &getCommands() const { return Commands; }
@@ -130,7 +132,9 @@ private:
public:
JobList();
+ virtual ~JobList();
+ /// Add a job to the list (taking ownership).
void addJob(Job *J) { Jobs.push_back(J); }
const list_type &getJobs() const { return Jobs; }
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 7f11c85ae35b..27ec12e4e4cd 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -121,7 +121,7 @@ public:
};
friend class ConcurrencyCheck;
- ASTUnit(bool MainFileIsAST);
+ ASTUnit(Diagnostic &Diag, bool MainFileIsAST);
~ASTUnit();
bool isMainFileAST() const { return MainFileIsAST; }
diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h
index ac5594e55d7d..5e8a4f144c96 100644
--- a/include/clang/Lex/PTHManager.h
+++ b/include/clang/Lex/PTHManager.h
@@ -115,7 +115,7 @@ public:
/// Unlike the version in IdentifierTable, this returns a pointer instead
/// of a reference. If the pointer is NULL then the IdentifierInfo cannot
/// be found.
- IdentifierInfo *get(const char *NameStart, const char *NameEnd);
+ IdentifierInfo *get(llvm::StringRef Name);
/// Create - This method creates PTHManager objects. The 'file' argument
/// is the name of the PTH file. This method returns NULL upon failure.
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 532d8e4b46f3..2b27a06070f8 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -547,7 +547,9 @@ public:
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
- std::string getSpelling(const Token &Tok) const;
+ ///
+ /// \param Invalid If non-NULL, will be set \c true if an error occurs.
+ std::string getSpelling(const Token &Tok, bool *Invalid = 0) const;
/// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a
/// token is the characters used to represent the token in the source file
@@ -556,7 +558,8 @@ public:
/// UCNs, etc.
static std::string getSpelling(const Token &Tok,
const SourceManager &SourceMgr,
- const LangOptions &Features);
+ const LangOptions &Features,
+ bool *Invalid = 0);
/// getSpelling - This method is used to get the spelling of a token into a
/// preallocated buffer, instead of as an std::string. The caller is required
@@ -568,17 +571,20 @@ public:
/// to point to a constant buffer with the data already in it (avoiding a
/// copy). The caller is not allowed to modify the returned buffer pointer
/// if an internal buffer is returned.
- unsigned getSpelling(const Token &Tok, const char *&Buffer) const;
+ unsigned getSpelling(const Token &Tok, const char *&Buffer,
+ bool *Invalid = 0) const;
/// getSpelling - This method is used to get the spelling of a token into a
/// SmallVector. Note that the returned StringRef may not point to the
/// supplied buffer if a copy can be avoided.
llvm::StringRef getSpelling(const Token &Tok,
- llvm::SmallVectorImpl<char> &Buffer) const;
+ llvm::SmallVectorImpl<char> &Buffer,
+ bool *Invalid = 0) const;
/// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant
/// with length 1, return the character.
- char getSpellingOfSingleCharacterNumericConstant(const Token &Tok) const {
+ char getSpellingOfSingleCharacterNumericConstant(const Token &Tok,
+ bool *Invalid = 0) const {
assert(Tok.is(tok::numeric_constant) &&
Tok.getLength() == 1 && "Called on unsupported token");
assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1");
@@ -730,7 +736,7 @@ public:
/// This code concatenates and consumes tokens up to the '>' token. It returns
/// false if the > was found, otherwise it returns true if it finds and consumes
/// the EOM marker.
- bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer);
+ bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer);
private:
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 26b10b58713e..8230cde3b2d5 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -423,10 +423,15 @@ namespace {
/// (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,
+isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
bool Member = false) {
+ bool Invalid = false;
const char *BufferStart
- = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin())).first;
+ = 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());
@@ -488,9 +493,12 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
// beginning of the file buffer.
std::pair<FileID, unsigned> DeclStartDecomp
= SourceMgr.getDecomposedLoc(DeclStartLoc);
+ bool Invalid = false;
const char *FileBufferStart
- = SourceMgr.getBufferData(DeclStartDecomp.first).first;
-
+ = 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) &&
@@ -971,22 +979,10 @@ void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
CollectNonClassIvars(OI, Ivars);
}
-void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
- for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(),
- E = PD->prop_end(); I != E; ++I)
- if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl())
- Ivars.push_back(Ivar);
-
- // Also look into nested protocols.
- for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(),
- E = PD->protocol_end(); P != E; ++P)
- CollectProtocolSynthesizedIvars(*P, Ivars);
-}
-
/// CollectNonClassIvars -
/// This routine collects all other ivars which are not declared in the class.
-/// This includes synthesized ivars and those in class's implementation.
+/// This includes synthesized ivars (via @synthesize) and those in
+// class's @implementation.
///
void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
@@ -997,21 +993,9 @@ void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI,
Ivars.push_back(*I);
}
}
-
- for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(),
- E = OI->prop_end(); I != E; ++I) {
- if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl())
- Ivars.push_back(Ivar);
- }
- // Also look into interface's protocol list for properties declared
- // in the protocol and whose ivars are synthesized.
- for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
- PE = OI->protocol_end(); P != PE; ++P) {
- ObjCProtocolDecl *PD = (*P);
- CollectProtocolSynthesizedIvars(PD, Ivars);
- }
- // Also add any ivar defined in this class's implementation
+ // Also add any ivar defined in this class's implementation. This
+ // includes synthesized ivars.
if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) {
for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
E = ImplDecl->ivar_end(); I != E; ++I)
@@ -4760,7 +4744,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return QualType();
case Type::Vector:
// FIXME: The merged type should be an ExtVector!
- if (areCompatVectorTypes(LHS->getAs<VectorType>(), RHS->getAs<VectorType>()))
+ if (areCompatVectorTypes(LHSCan->getAs<VectorType>(),
+ RHSCan->getAs<VectorType>()))
return LHS;
return QualType();
case Type::ObjCInterface: {
@@ -4997,13 +4982,24 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
Done = false;
while (!Done) {
- switch (*Str++) {
+ switch (char c = *Str++) {
default: Done = true; --Str; break;
case '*':
- Type = Context.getPointerType(Type);
- break;
case '&':
- Type = Context.getLValueReferenceType(Type);
+ {
+ // Both pointers and references can have their pointee types
+ // qualified with an address space.
+ char *End;
+ unsigned AddrSpace = strtoul(Str, &End, 10);
+ if (End != Str && AddrSpace != 0) {
+ Type = Context.getAddrSpaceQualType(Type, AddrSpace);
+ Str = End;
+ }
+ }
+ if (c == '*')
+ Type = Context.getPointerType(Type);
+ else
+ Type = Context.getLValueReferenceType(Type);
break;
// FIXME: There's no way to have a built-in with an rvalue ref arg.
case 'C':
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index d9c0d7b6bed4..dd2528a6b3b3 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1592,6 +1592,12 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
Name.getAsIdentifierInfo(),
Importer.Import(D->getTagKeywordLoc()),
0);
+ // Import the qualifier, if any.
+ if (D->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+ SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+ D2->setQualifierInfo(NNS, NNSRange);
+ }
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, D2);
@@ -1734,6 +1740,12 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Name.getAsIdentifierInfo(),
Importer.Import(D->getTagKeywordLoc()));
}
+ // Import the qualifier, if any.
+ if (D->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+ SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+ D2->setQualifierInfo(NNS, NNSRange);
+ }
D2->setLexicalDeclContext(LexicalDC);
LexicalDC->addDecl(D2);
}
@@ -1900,6 +1912,13 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
D->isInlineSpecified(),
D->hasWrittenPrototype());
}
+
+ // Import the qualifier, if any.
+ if (D->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+ SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+ ToFunction->setQualifierInfo(NNS, NNSRange);
+ }
ToFunction->setAccess(D->getAccess());
ToFunction->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToFunction);
@@ -2110,6 +2129,12 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
Name.getAsIdentifierInfo(), T, TInfo,
D->getStorageClass());
+ // Import the qualifier, if any.
+ if (D->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+ SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+ ToVar->setQualifierInfo(NNS, NNSRange);
+ }
ToVar->setAccess(D->getAccess());
ToVar->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToVar);
@@ -2176,6 +2201,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
/*FIXME: Default argument*/ 0);
+ ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
return Importer.Imported(D, ToParm);
}
@@ -3063,7 +3089,7 @@ FileID ASTImporter::Import(FileID FromID) {
FromSLoc.getFile().getFileCharacteristic());
} else {
// FIXME: We want to re-use the existing MemoryBuffer!
- const llvm::MemoryBuffer *FromBuf = Cache->getBuffer();
+ const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags());
llvm::MemoryBuffer *ToBuf
= llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBufferStart(),
FromBuf->getBufferEnd(),
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 2f1a6af77aa9..3408a1e3cc74 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_library(clangAST
Decl.cpp
DeclBase.cpp
DeclCXX.cpp
+ DeclFriend.cpp
DeclGroup.cpp
DeclObjC.cpp
DeclPrinter.cpp
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 23f5fba437a5..f568d1cdd45e 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -495,9 +495,16 @@ NamedDecl *NamedDecl::getUnderlyingDecl() {
// DeclaratorDecl Implementation
//===----------------------------------------------------------------------===//
+DeclaratorDecl::~DeclaratorDecl() {}
+void DeclaratorDecl::Destroy(ASTContext &C) {
+ if (hasExtInfo())
+ C.Deallocate(getExtInfo());
+ ValueDecl::Destroy(C);
+}
+
SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
if (DeclInfo) {
- TypeLoc TL = DeclInfo->getTypeLoc();
+ TypeLoc TL = getTypeSourceInfo()->getTypeLoc();
while (true) {
TypeLoc NextTL = TL.getNextTypeLoc();
if (!NextTL)
@@ -508,6 +515,36 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
return SourceLocation();
}
+void DeclaratorDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange) {
+ if (Qualifier) {
+ // Make sure the extended decl info is allocated.
+ if (!hasExtInfo()) {
+ // Save (non-extended) type source info pointer.
+ TypeSourceInfo *savedTInfo = DeclInfo.get<TypeSourceInfo*>();
+ // Allocate external info struct.
+ DeclInfo = new (getASTContext()) ExtInfo;
+ // Restore savedTInfo into (extended) decl info.
+ getExtInfo()->TInfo = savedTInfo;
+ }
+ // Set qualifier info.
+ getExtInfo()->NNS = Qualifier;
+ getExtInfo()->NNSRange = QualifierRange;
+ }
+ else {
+ // Here Qualifier == 0, i.e., we are removing the qualifier (if any).
+ assert(QualifierRange.isInvalid());
+ if (hasExtInfo()) {
+ // Save type source info pointer.
+ TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
+ // Deallocate the extended decl info.
+ getASTContext().Deallocate(getExtInfo());
+ // Restore savedTInfo into (non-extended) decl info.
+ DeclInfo = savedTInfo;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// VarDecl Implementation
//===----------------------------------------------------------------------===//
@@ -542,7 +579,7 @@ void VarDecl::Destroy(ASTContext& C) {
}
}
this->~VarDecl();
- C.Deallocate((void *)this);
+ DeclaratorDecl::Destroy(C);
}
VarDecl::~VarDecl() {
@@ -818,7 +855,7 @@ void FunctionDecl::Destroy(ASTContext& C) {
C.Deallocate(ParamInfo);
- Decl::Destroy(C);
+ DeclaratorDecl::Destroy(C);
}
void FunctionDecl::getNameForDiagnostic(std::string &S,
@@ -1348,6 +1385,12 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
// TagDecl Implementation
//===----------------------------------------------------------------------===//
+void TagDecl::Destroy(ASTContext &C) {
+ if (hasExtInfo())
+ C.Deallocate(getExtInfo());
+ TypeDecl::Destroy(C);
+}
+
SourceRange TagDecl::getSourceRange() const {
SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation();
return SourceRange(TagKeywordLoc, E);
@@ -1409,6 +1452,26 @@ TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
}
}
+void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange) {
+ if (Qualifier) {
+ // Make sure the extended qualifier info is allocated.
+ if (!hasExtInfo())
+ TypedefDeclOrQualifier = new (getASTContext()) ExtInfo;
+ // Set qualifier info.
+ getExtInfo()->NNS = Qualifier;
+ getExtInfo()->NNSRange = QualifierRange;
+ }
+ else {
+ // Here Qualifier == 0, i.e., we are removing the qualifier (if any).
+ assert(QualifierRange.isInvalid());
+ if (hasExtInfo()) {
+ getASTContext().Deallocate(getExtInfo());
+ TypedefDeclOrQualifier = (TypedefDecl*) 0;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// EnumDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1422,7 +1485,7 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
}
void EnumDecl::Destroy(ASTContext& C) {
- Decl::Destroy(C);
+ TagDecl::Destroy(C);
}
void EnumDecl::completeDefinition(QualType NewType,
@@ -1529,7 +1592,7 @@ void NamespaceDecl::Destroy(ASTContext& C) {
// together. They are all top-level Decls.
this->~NamespaceDecl();
- C.Deallocate((void *)this);
+ Decl::Destroy(C);
}
@@ -1563,7 +1626,7 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
void EnumConstantDecl::Destroy(ASTContext& C) {
if (Init) Init->Destroy(C);
- Decl::Destroy(C);
+ ValueDecl::Destroy(C);
}
TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index a9495343e887..1aac7cfd598a 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExternalASTSource.h"
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 7f4ad34fb7f8..37f7479b36cd 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -33,7 +33,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialDestructor(true), ComputedVisibleConversions(false),
Bases(0), NumBases(0), VBases(0), NumVBases(0),
- Definition(D) {
+ Definition(D), FirstFriend(0) {
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -318,105 +318,128 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
data().PlainOldData = false;
}
-void
-CXXRecordDecl::collectConversionFunctions(
- llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const
-{
- const UnresolvedSetImpl *Cs = getConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
- I != E; ++I) {
- NamedDecl *TopConv = *I;
- CanQualType TConvType;
- if (FunctionTemplateDecl *TConversionTemplate =
- dyn_cast<FunctionTemplateDecl>(TopConv))
- TConvType =
- getASTContext().getCanonicalType(
- TConversionTemplate->getTemplatedDecl()->getResultType());
- else
- TConvType =
- getASTContext().getCanonicalType(
- cast<CXXConversionDecl>(TopConv)->getConversionType());
- ConversionsTypeSet.insert(TConvType);
- }
-}
-
-/// getNestedVisibleConversionFunctions - imports unique conversion
-/// functions from base classes into the visible conversion function
-/// list of the class 'RD'. This is a private helper method.
-/// TopConversionsTypeSet is the set of conversion functions of the class
-/// we are interested in. HiddenConversionTypes is set of conversion functions
-/// of the immediate derived class which hides the conversion functions found
-/// in current class.
-void
-CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
- const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet,
- const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes)
-{
- bool inTopClass = (RD == this);
- QualType ClassType = getASTContext().getTypeDeclType(this);
- if (const RecordType *Record = ClassType->getAs<RecordType>()) {
- const UnresolvedSetImpl *Cs
- = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
-
- for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
- I != E; ++I) {
- NamedDecl *Conv = *I;
- // Only those conversions not exact match of conversions in current
- // class are candidateconversion routines.
- CanQualType ConvType;
- if (FunctionTemplateDecl *ConversionTemplate =
- dyn_cast<FunctionTemplateDecl>(Conv))
- ConvType =
- getASTContext().getCanonicalType(
- ConversionTemplate->getTemplatedDecl()->getResultType());
- else
- ConvType =
- getASTContext().getCanonicalType(
- cast<CXXConversionDecl>(Conv)->getConversionType());
- // We only add conversion functions found in the base class if they
- // are not hidden by those found in HiddenConversionTypes which are
- // the conversion functions in its derived class.
- if (inTopClass ||
- (!TopConversionsTypeSet.count(ConvType) &&
- !HiddenConversionTypes.count(ConvType)) ) {
- if (FunctionTemplateDecl *ConversionTemplate =
- dyn_cast<FunctionTemplateDecl>(Conv))
- RD->addVisibleConversionFunction(ConversionTemplate);
+static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
+ QualType T;
+ if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv))
+ T = ConvTemp->getTemplatedDecl()->getResultType();
+ else
+ T = cast<CXXConversionDecl>(Conv)->getConversionType();
+ return Context.getCanonicalType(T);
+}
+
+/// Collect the visible conversions of a base class.
+///
+/// \param Base a base class of the class we're considering
+/// \param InVirtual whether this base class is a virtual base (or a base
+/// of a virtual base)
+/// \param Access the access along the inheritance path to this base
+/// \param ParentHiddenTypes the conversions provided by the inheritors
+/// of this base
+/// \param Output the set to which to add conversions from non-virtual bases
+/// \param VOutput the set to which to add conversions from virtual bases
+/// \param HiddenVBaseCs the set of conversions which were hidden in a
+/// virtual base along some inheritance path
+static void CollectVisibleConversions(ASTContext &Context,
+ CXXRecordDecl *Record,
+ bool InVirtual,
+ AccessSpecifier Access,
+ const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
+ UnresolvedSetImpl &Output,
+ UnresolvedSetImpl &VOutput,
+ llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
+ // The set of types which have conversions in this class or its
+ // subclasses. As an optimization, we don't copy the derived set
+ // unless it might change.
+ const llvm::SmallPtrSet<CanQualType, 8> *HiddenTypes = &ParentHiddenTypes;
+ llvm::SmallPtrSet<CanQualType, 8> HiddenTypesBuffer;
+
+ // Collect the direct conversions and figure out which conversions
+ // will be hidden in the subclasses.
+ UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
+ if (!Cs.empty()) {
+ HiddenTypesBuffer = ParentHiddenTypes;
+ HiddenTypes = &HiddenTypesBuffer;
+
+ for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) {
+ bool Hidden =
+ !HiddenTypesBuffer.insert(GetConversionType(Context, I.getDecl()));
+
+ // If this conversion is hidden and we're in a virtual base,
+ // remember that it's hidden along some inheritance path.
+ if (Hidden && InVirtual)
+ HiddenVBaseCs.insert(cast<NamedDecl>(I.getDecl()->getCanonicalDecl()));
+
+ // If this conversion isn't hidden, add it to the appropriate output.
+ else if (!Hidden) {
+ AccessSpecifier IAccess
+ = CXXRecordDecl::MergeAccess(Access, I.getAccess());
+
+ if (InVirtual)
+ VOutput.addDecl(I.getDecl(), IAccess);
else
- RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv));
+ Output.addDecl(I.getDecl(), IAccess);
}
}
}
- if (getNumBases() == 0 && getNumVBases() == 0)
- return;
+ // Collect information recursively from any base classes.
+ for (CXXRecordDecl::base_class_iterator
+ I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
+ const RecordType *RT = I->getType()->getAs<RecordType>();
+ if (!RT) continue;
- llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions;
- if (!inTopClass)
- collectConversionFunctions(ConversionFunctions);
+ AccessSpecifier BaseAccess
+ = CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier());
+ bool BaseInVirtual = InVirtual || I->isVirtual();
- for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(),
- E = vbases_end(); VBase != E; ++VBase) {
- if (const RecordType *RT = VBase->getType()->getAs<RecordType>()) {
- CXXRecordDecl *VBaseClassDecl
- = cast<CXXRecordDecl>(RT->getDecl());
- VBaseClassDecl->getNestedVisibleConversionFunctions(RD,
- TopConversionsTypeSet,
- (inTopClass ? TopConversionsTypeSet : ConversionFunctions));
- }
+ CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
+ CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess,
+ *HiddenTypes, Output, VOutput, HiddenVBaseCs);
}
- for (CXXRecordDecl::base_class_iterator Base = bases_begin(),
- E = bases_end(); Base != E; ++Base) {
- if (Base->isVirtual())
- continue;
- if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(RT->getDecl());
+}
- BaseClassDecl->getNestedVisibleConversionFunctions(RD,
- TopConversionsTypeSet,
- (inTopClass ? TopConversionsTypeSet : ConversionFunctions));
- }
+/// Collect the visible conversions of a class.
+///
+/// This would be extremely straightforward if it weren't for virtual
+/// bases. It might be worth special-casing that, really.
+static void CollectVisibleConversions(ASTContext &Context,
+ CXXRecordDecl *Record,
+ UnresolvedSetImpl &Output) {
+ // The collection of all conversions in virtual bases that we've
+ // found. These will be added to the output as long as they don't
+ // appear in the hidden-conversions set.
+ UnresolvedSet<8> VBaseCs;
+
+ // The set of conversions in virtual bases that we've determined to
+ // be hidden.
+ llvm::SmallPtrSet<NamedDecl*, 8> HiddenVBaseCs;
+
+ // The set of types hidden by classes derived from this one.
+ llvm::SmallPtrSet<CanQualType, 8> HiddenTypes;
+
+ // Go ahead and collect the direct conversions and add them to the
+ // hidden-types set.
+ UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
+ Output.append(Cs.begin(), Cs.end());
+ for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I)
+ HiddenTypes.insert(GetConversionType(Context, I.getDecl()));
+
+ // Recursively collect conversions from base classes.
+ for (CXXRecordDecl::base_class_iterator
+ I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
+ const RecordType *RT = I->getType()->getAs<RecordType>();
+ if (!RT) continue;
+
+ CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()),
+ I->isVirtual(), I->getAccessSpecifier(),
+ HiddenTypes, Output, VBaseCs, HiddenVBaseCs);
+ }
+
+ // Add any unhidden conversions provided by virtual bases.
+ for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end();
+ I != E; ++I) {
+ if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())))
+ Output.addDecl(I.getDecl(), I.getAccess());
}
}
@@ -429,37 +452,27 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
// If visible conversion list is already evaluated, return it.
if (data().ComputedVisibleConversions)
return &data().VisibleConversions;
- llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet;
- collectConversionFunctions(TopConversionsTypeSet);
- getNestedVisibleConversionFunctions(this, TopConversionsTypeSet,
- TopConversionsTypeSet);
+ CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
data().ComputedVisibleConversions = true;
return &data().VisibleConversions;
}
-void CXXRecordDecl::addVisibleConversionFunction(
- CXXConversionDecl *ConvDecl) {
- assert(!ConvDecl->getDescribedFunctionTemplate() &&
- "Conversion function templates should cast to FunctionTemplateDecl.");
- data().VisibleConversions.addDecl(ConvDecl);
-}
-
-void CXXRecordDecl::addVisibleConversionFunction(
- FunctionTemplateDecl *ConvDecl) {
- assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
- "Function template is not a conversion function template");
- data().VisibleConversions.addDecl(ConvDecl);
-}
-
void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
+ assert(ConvDecl->getDeclContext() == this &&
+ "conversion function does not belong to this record");
+
+ // We intentionally don't use the decl's access here because it
+ // hasn't been set yet. That's really just a misdesign in Sema.
data().Conversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
+ assert(ConvDecl->getDeclContext() == this &&
+ "conversion function does not belong to this record");
data().Conversions.addDecl(ConvDecl);
}
@@ -846,28 +859,6 @@ CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
return new (C) CXXConversionDecl(RD, L, N, T, TInfo, isInline, isExplicit);
}
-FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- FriendUnion Friend,
- SourceLocation FriendL) {
-#ifndef NDEBUG
- if (Friend.is<NamedDecl*>()) {
- NamedDecl *D = Friend.get<NamedDecl*>();
- assert(isa<FunctionDecl>(D) ||
- isa<CXXRecordDecl>(D) ||
- isa<FunctionTemplateDecl>(D) ||
- isa<ClassTemplateDecl>(D));
-
- // As a temporary hack, we permit template instantiation to point
- // to the original declaration when instantiating members.
- assert(D->getFriendObjectKind() ||
- (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
- }
-#endif
-
- return new (C) FriendDecl(DC, L, Friend, FriendL);
-}
-
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
@@ -952,8 +943,7 @@ StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
void StaticAssertDecl::Destroy(ASTContext& C) {
AssertExpr->Destroy(C);
Message->Destroy(C);
- this->~StaticAssertDecl();
- C.Deallocate((void *)this);
+ Decl::Destroy(C);
}
StaticAssertDecl::~StaticAssertDecl() {
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
new file mode 100644
index 000000000000..ab3552db28e0
--- /dev/null
+++ b/lib/AST/DeclFriend.cpp
@@ -0,0 +1,41 @@
+//===--- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation --===//
+//
+// 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 AST classes related to C++ friend
+// declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclTemplate.h"
+using namespace clang;
+
+FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ FriendUnion Friend,
+ SourceLocation FriendL) {
+#ifndef NDEBUG
+ if (Friend.is<NamedDecl*>()) {
+ NamedDecl *D = Friend.get<NamedDecl*>();
+ assert(isa<FunctionDecl>(D) ||
+ isa<CXXRecordDecl>(D) ||
+ isa<FunctionTemplateDecl>(D) ||
+ isa<ClassTemplateDecl>(D));
+
+ // As a temporary hack, we permit template instantiation to point
+ // to the original declaration when instantiating members.
+ assert(D->getFriendObjectKind() ||
+ (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
+ }
+#endif
+
+ FriendDecl *FD = new (C) FriendDecl(DC, L, Friend, FriendL);
+ cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
+ return FD;
+}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 67b71a0c44e5..7d1033d4f15f 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -89,47 +89,69 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
return 0;
}
+ObjCPropertyDecl *
+ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
+ IdentifierInfo *propertyID) {
+
+ DeclContext::lookup_const_iterator I, E;
+ llvm::tie(I, E) = DC->lookup(propertyID);
+ for ( ; I != E; ++I)
+ if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I))
+ return PD;
+
+ return 0;
+}
+
/// FindPropertyDeclaration - Finds declaration of the property given its name
/// in 'PropertyId' and returns it. It returns 0, if not found.
-/// FIXME: Convert to DeclContext lookup...
-///
ObjCPropertyDecl *
ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
- for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I)
- if ((*I)->getIdentifier() == PropertyId)
- return *I;
-
- const ObjCProtocolDecl *PID = dyn_cast<ObjCProtocolDecl>(this);
- if (PID) {
- for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
- E = PID->protocol_end(); I != E; ++I)
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
- return P;
- }
- if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this)) {
- // Look through categories.
- for (ObjCCategoryDecl *Category = OID->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
- if (!Category->IsClassExtension())
- if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId))
+ if (ObjCPropertyDecl *PD =
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
+ return PD;
+
+ switch (getKind()) {
+ default:
+ break;
+ case Decl::ObjCProtocol: {
+ const ObjCProtocolDecl *PID = cast<ObjCProtocolDecl>(this);
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
+ E = PID->protocol_end(); I != E; ++I)
+ if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
+ break;
}
- // Look through protocols.
- for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(),
- E = OID->protocol_end(); I != E; ++I) {
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
- return P;
+ case Decl::ObjCInterface: {
+ const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this);
+ // Look through categories.
+ for (ObjCCategoryDecl *Cat = OID->getCategoryList();
+ Cat; Cat = Cat->getNextClassCategory())
+ if (!Cat->IsClassExtension())
+ if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId))
+ return P;
+
+ // Look through protocols.
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = OID->protocol_begin(), E = OID->protocol_end(); I != E; ++I)
+ if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
+ return P;
+
+ // Finally, check the super class.
+ if (const ObjCInterfaceDecl *superClass = OID->getSuperClass())
+ return superClass->FindPropertyDeclaration(PropertyId);
+ break;
}
- if (OID->getSuperClass())
- return OID->getSuperClass()->FindPropertyDeclaration(PropertyId);
- } else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) {
- // Look through protocols.
- if (!OCD->IsClassExtension())
- for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
- E = OCD->protocol_end(); I != E; ++I) {
+ case Decl::ObjCCategory: {
+ const ObjCCategoryDecl *OCD = cast<ObjCCategoryDecl>(this);
+ // Look through protocols.
+ if (!OCD->IsClassExtension())
+ for (ObjCCategoryDecl::protocol_iterator
+ I = OCD->protocol_begin(), E = OCD->protocol_end(); I != E; ++I)
if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
+
+ break;
}
}
return 0;
@@ -137,22 +159,21 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
/// with name 'PropertyId' in the primary class; including those in protocols
-/// (direct or indirect) used by the promary class.
-/// FIXME: Convert to DeclContext lookup...
+/// (direct or indirect) used by the primary class.
///
ObjCPropertyDecl *
-ObjCContainerDecl::FindPropertyVisibleInPrimaryClass(
+ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
IdentifierInfo *PropertyId) const {
- assert(isa<ObjCInterfaceDecl>(this) && "FindPropertyVisibleInPrimaryClass");
- for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I)
- if ((*I)->getIdentifier() == PropertyId)
- return *I;
- const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this);
+ if (ObjCPropertyDecl *PD =
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
+ return PD;
+
// Look through protocols.
- for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(),
- E = OID->protocol_end(); I != E; ++I)
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = protocol_begin(), E = protocol_end(); I != E; ++I)
if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
+
return 0;
}
@@ -441,7 +462,6 @@ void ObjCInterfaceDecl::Destroy(ASTContext &C) {
for (ivar_iterator I = ivar_begin(), E = ivar_end(); I != E; ++I)
if (*I) (*I)->Destroy(C);
- IVars.Destroy(C);
// FIXME: CategoryList?
// FIXME: Because there is no clear ownership
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index efd0fd1b8dcb..1b3202dd4282 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -788,6 +788,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
switch (getStmtClass()) {
default:
+ if (getType()->isVoidType())
+ return false;
Loc = getExprLoc();
R1 = getSourceRange();
return true;
@@ -834,8 +836,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
if (IE->getValue() == 0)
return false;
- return (BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
- BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
+ return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
+ BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
}
if (BO->isAssignmentOp())
@@ -936,6 +938,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
if (const Expr *E = dyn_cast<Expr>(CS->body_back()))
return E->isUnusedResultAWarning(Loc, R1, R2, Ctx);
+ if (getType()->isVoidType())
+ return false;
Loc = cast<StmtExpr>(this)->getLParenLoc();
R1 = getSourceRange();
return true;
@@ -949,6 +953,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange();
return true;
case CXXFunctionalCastExprClass: {
+ if (getType()->isVoidType())
+ return false;
const CastExpr *CE = cast<CastExpr>(this);
// If this is a cast to void or a constructor conversion, check the operand.
diff --git a/lib/AST/Makefile b/lib/AST/Makefile
index 8afc629d6b3b..ede25777c90b 100644
--- a/lib/AST/Makefile
+++ b/lib/AST/Makefile
@@ -15,7 +15,7 @@ LEVEL = ../../../..
LIBRARYNAME := clangAST
BUILD_ARCHIVE = 1
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index 838753a1433f..ade2483722ef 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -38,17 +38,15 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignm
// Constructor for C++ records.
ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx,
- uint64_t size, unsigned alignment,
- uint64_t datasize,
- const uint64_t *fieldoffsets,
- unsigned fieldcount,
- uint64_t nonvirtualsize,
- unsigned nonvirtualalign,
- const PrimaryBaseInfo &PrimaryBase,
- const std::pair<const CXXRecordDecl *, uint64_t> *bases,
- unsigned numbases,
- const std::pair<const CXXRecordDecl *, uint64_t> *vbases,
- unsigned numvbases)
+ uint64_t size, unsigned alignment,
+ uint64_t datasize,
+ const uint64_t *fieldoffsets,
+ unsigned fieldcount,
+ uint64_t nonvirtualsize,
+ unsigned nonvirtualalign,
+ const PrimaryBaseInfo &PrimaryBase,
+ const BaseOffsetsMapTy& BaseOffsets,
+ const BaseOffsetsMapTy& VBaseOffsets)
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
FieldCount(fieldcount), CXXInfo(new (Ctx) CXXRecordLayoutInfo)
{
@@ -60,8 +58,17 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx,
CXXInfo->PrimaryBase = PrimaryBase;
CXXInfo->NonVirtualSize = nonvirtualsize;
CXXInfo->NonVirtualAlign = nonvirtualalign;
- for (unsigned i = 0; i != numbases; ++i)
- CXXInfo->BaseOffsets[bases[i].first] = bases[i].second;
- for (unsigned i = 0; i != numvbases; ++i)
- CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second;
+ CXXInfo->BaseOffsets = BaseOffsets;
+ CXXInfo->VBaseOffsets = VBaseOffsets;
+
+#ifndef NDEBUG
+ if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
+ if (getPrimaryBaseWasVirtual())
+ assert(getVBaseClassOffset(PrimaryBase) == 0 &&
+ "Primary virtual base must be at offset 0!");
+ else
+ assert(getBaseClassOffset(PrimaryBase) == 0 &&
+ "Primary base must be at offset 0!");
+ }
+#endif
}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 22285ca42032..93edb42bf4c0 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -23,43 +23,8 @@ using namespace clang;
ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
: Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0),
MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0),
- NonVirtualAlignment(8) { }
+ NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { }
-/// LayoutVtable - Lay out the vtable and set PrimaryBase.
-void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
- if (!RD->isDynamicClass()) {
- // There is no primary base in this case.
- return;
- }
-
- SelectPrimaryBase(RD);
- if (!PrimaryBase.getBase()) {
- int AS = 0;
- UpdateAlignment(Ctx.Target.getPointerAlign(AS));
- Size += Ctx.Target.getPointerWidth(AS);
- DataSize = Size;
- }
-}
-
-void
-ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- if (!i->isVirtual()) {
- assert(!i->getType()->isDependentType() &&
- "Cannot layout class with dependent bases.");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- // Skip the PrimaryBase here, as it is laid down first.
- if (Base != PrimaryBase.getBase() || PrimaryBase.isVirtual())
- LayoutBaseNonVirtually(Base, false);
- }
- }
-}
-
-// Helper routines related to the abi definition from:
-// http://www.codesourcery.com/public/cxx-abi/abi.html
-//
/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
/// no other data.
bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
@@ -97,44 +62,48 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
}
void
-ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
- const CXXRecordDecl *&FirstPrimary) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- assert(!i->getType()->isDependentType() &&
+ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
+
const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (!i->isVirtual()) {
- SelectPrimaryVBase(Base, FirstPrimary);
- if (PrimaryBase.getBase())
- return;
- continue;
- }
- if (IsNearlyEmpty(Base)) {
- if (FirstPrimary==0)
- FirstPrimary = Base;
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Check if this is a nearly empty virtual base.
+ if (I->isVirtual() && IsNearlyEmpty(Base)) {
+ // If it's not an indirect primary base, then we've found our primary
+ // base.
if (!IndirectPrimaryBases.count(Base)) {
- setPrimaryBase(Base, /*IsVirtual=*/true);
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base,
+ /*IsVirtual=*/true);
return;
}
+
+ // Is this the first nearly empty virtual base?
+ if (!FirstNearlyEmptyVBase)
+ FirstNearlyEmptyVBase = Base;
}
- assert(i->isVirtual());
- SelectPrimaryVBase(Base, FirstPrimary);
+
+ SelectPrimaryVBase(Base);
if (PrimaryBase.getBase())
return;
}
}
-/// SelectPrimaryBase - Selects the primary base for the given class and
-/// record that with setPrimaryBase. We also calculate the IndirectPrimaries.
-void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
+/// DeterminePrimaryBase - Determine the primary base of the given class.
+void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
+ // If the class isn't dynamic, it won't have a primary base.
+ if (!RD->isDynamicClass())
+ return;
+
// Compute all the primary virtual bases for all of our direct and
// indirect bases, and record all their primary virtual base classes.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end(); i != e; ++i) {
assert(!i->getType()->isDependentType() &&
- "Cannot layout class with dependent bases.");
+ "Cannot lay out class with dependent bases.");
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
IdentifyPrimaryBases(Base);
@@ -161,90 +130,201 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
// Otherwise, it is the first nearly empty virtual base that is not an
// indirect primary virtual base class, if one exists.
+ if (RD->getNumVBases() != 0) {
+ SelectPrimaryVBase(RD);
+ if (PrimaryBase.getBase())
+ return;
+ }
- // If we have no virtual bases at this point, bail out as the searching below
- // is expensive.
- if (RD->getNumVBases() == 0)
+ // Otherwise, it is the first nearly empty virtual base that is not an
+ // indirect primary virtual base class, if one exists.
+ if (FirstNearlyEmptyVBase) {
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase,
+ /*IsVirtual=*/true);
return;
+ }
- // Then we can search for the first nearly empty virtual base itself.
- const CXXRecordDecl *FirstPrimary = 0;
- SelectPrimaryVBase(RD, FirstPrimary);
-
- // Otherwise if is the first nearly empty virtual base, if one exists,
- // otherwise there is no primary base class.
- if (!PrimaryBase.getBase())
- setPrimaryBase(FirstPrimary, /*IsVirtual=*/true);
-}
+ // Otherwise there is no primary base class.
+ assert(!PrimaryBase.getBase() && "Should not get here with a primary base!");
-void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
- LayoutBaseNonVirtually(RD, true);
+ // Allocate the virtual table pointer at offset zero.
+ assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
+
+ // Update the size.
+ Size += Ctx.Target.getPointerWidth(0);
+ DataSize = Size;
+
+ // Update the alignment.
+ UpdateAlignment(Ctx.Target.getPointerAlign(0));
}
-uint64_t ASTRecordLayoutBuilder::getBaseOffset(const CXXRecordDecl *Base) {
- for (size_t i = 0; i < Bases.size(); ++i) {
- if (Bases[i].first == Base)
- return Bases[i].second;
+void
+ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
+ // First, determine the primary base class.
+ DeterminePrimaryBase(RD);
+
+ // If we have a primary base class, lay it out.
+ if (const CXXRecordDecl *Base = PrimaryBase.getBase()) {
+ if (PrimaryBase.isVirtual()) {
+ // We have a virtual primary base, insert it as an indirect primary base.
+ IndirectPrimaryBases.insert(Base);
+
+ LayoutVirtualBase(Base);
+ } else
+ LayoutNonVirtualBase(Base);
}
- for (size_t i = 0; i < VBases.size(); ++i) {
- if (VBases[i].first == Base)
- return VBases[i].second;
+
+ // Now lay out the non-virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+
+ // Ignore virtual bases.
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Skip the primary base.
+ if (Base == PrimaryBase.getBase() && !PrimaryBase.isVirtual())
+ continue;
+
+ // Lay out the base.
+ LayoutNonVirtualBase(Base);
}
- assert(0 && "missing base");
- return 0;
}
+void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
+ // Layout the base.
+ uint64_t Offset = LayoutBase(RD);
+
+ // Add its base class offset.
+ if (!Bases.insert(std::make_pair(RD, Offset)).second)
+ assert(false && "Added same base offset more than once!");
+}
-void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class,
- const CXXRecordDecl *RD,
- const CXXRecordDecl *PB,
- uint64_t Offset,
- llvm::SmallSet<const CXXRecordDecl*, 32> &mark,
- llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- assert(!i->getType()->isDependentType() &&
+void
+ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
+ uint64_t Offset,
+ const CXXRecordDecl *MostDerivedClass) {
+ const CXXRecordDecl *PrimaryBase;
+
+ if (MostDerivedClass == RD)
+ PrimaryBase = this->PrimaryBase.getBase();
+ else {
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ PrimaryBase = Layout.getPrimaryBase();
+ }
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
+
const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseOffset = Offset;
- if (i->isVirtual()) {
- if (Base == PB) {
- // Only lay things out once.
- if (mark.count(Base))
- continue;
- // Mark it so we don't lay it out twice.
- mark.insert(Base);
- assert (IndirectPrimary.count(Base) && "IndirectPrimary was wrong");
- VBases.push_back(std::make_pair(Base, Offset));
- } else if (IndirectPrimary.count(Base)) {
- // Someone else will eventually lay this out.
- ;
- } else {
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ if (I->isVirtual()) {
+ bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base);
+
+ // We only want to visit this virtual base if it's either a primary base,
+ // or not an indirect primary base.
+ if (Base == PrimaryBase || !IndirectPrimaryBase) {
// Only lay things out once.
- if (mark.count(Base))
+ if (!VisitedVirtualBases.insert(Base))
continue;
- // Mark it so we don't lay it out twice.
- mark.insert(Base);
- LayoutVirtualBase(Base);
- BaseOffset = VBases.back().second;
- }
- } else {
- if (RD == Class)
- BaseOffset = getBaseOffset(Base);
- else {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+
+ if (Base == PrimaryBase) {
+ assert(IndirectPrimaryBase &&
+ "Base is supposed to be an indirect primary base!");
+
+ // We only want to add a vbase offset if this primary base is not the
+ // primary base of the most derived class.
+ if (PrimaryBase != this->PrimaryBase.getBase() ||
+ !this->PrimaryBase.isVirtual()) {
+ if (!VBases.insert(std::make_pair(Base, Offset)).second)
+ assert(false && "Added same vbase offset more than once!");
+ }
+ } else {
+ // We actually do want to lay out this base.
+ LayoutVirtualBase(Base);
+ }
}
}
- if (Base->getNumVBases()) {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Base);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBaseInfo().getBase();
- LayoutVirtualBases(Class, Base, PrimaryBase, BaseOffset, mark,
- IndirectPrimary);
+ if (!Base->getNumVBases()) {
+ // This base isn't interesting since it doesn't have any virtual bases.
+ continue;
+ }
+
+ // Compute the offset of this base.
+ uint64_t BaseOffset;
+
+ if (I->isVirtual()) {
+ // We want the vbase offset from the class we're currently laying out.
+ assert(VBases.count(Base) && "Did not find virtual base!");
+ BaseOffset = VBases[Base];
+ } else if (RD == MostDerivedClass) {
+ // We want the base offset from the class we're currently laying out.
+ assert(Bases.count(Base) && "Did not find base!");
+ BaseOffset = Bases[Base];
+ } else {
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ BaseOffset = Offset + Layout.getBaseClassOffset(Base);
}
+
+ LayoutVirtualBases(Base, BaseOffset, MostDerivedClass);
+ }
+}
+
+void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
+ // Layout the base.
+ uint64_t Offset = LayoutBase(RD);
+
+ // Add its base class offset.
+ if (!VBases.insert(std::make_pair(RD, Offset)).second)
+ assert(false && "Added same vbase offset more than once!");
+}
+
+uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
+ const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
+
+ // If we have an empty base class, try to place it at offset 0.
+ if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
+ // We were able to place the class at offset 0.
+ UpdateEmptyClassOffsets(RD, 0);
+
+ Size = std::max(Size, BaseInfo.getSize());
+
+ return 0;
+ }
+
+ unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
+
+ // Round up the current record size to the base's alignment boundary.
+ uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
+
+ // Try to place the base.
+ while (true) {
+ if (canPlaceRecordAtOffset(RD, Offset))
+ break;
+
+ Offset += BaseAlign;
}
+
+ if (!RD->isEmpty()) {
+ // Update the data size.
+ DataSize = Offset + BaseInfo.getNonVirtualSize();
+
+ Size = std::max(Size, DataSize);
+ } else
+ Size = std::max(Size, Offset + BaseInfo.getSize());
+
+ // Remember max struct/class alignment.
+ UpdateAlignment(BaseAlign);
+
+ UpdateEmptyClassOffsets(RD, Offset);
+ return Offset;
}
bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
@@ -393,59 +473,6 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
}
}
-uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
- const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
-
- // If we have an empty base class, try to place it at offset 0.
- if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
- // We were able to place the class at offset 0.
- UpdateEmptyClassOffsets(RD, 0);
-
- Size = std::max(Size, BaseInfo.getSize());
-
- return 0;
- }
-
- unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
-
- // Round up the current record size to the base's alignment boundary.
- uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
-
- // Try to place the base.
- while (true) {
- if (canPlaceRecordAtOffset(RD, Offset))
- break;
-
- Offset += BaseAlign;
- }
-
- if (!RD->isEmpty()) {
- // Update the data size.
- DataSize = Offset + BaseInfo.getNonVirtualSize();
-
- Size = std::max(Size, DataSize);
- } else
- Size = std::max(Size, Offset + BaseInfo.getSize());
-
- // Remember max struct/class alignment.
- UpdateAlignment(BaseAlign);
-
- UpdateEmptyClassOffsets(RD, Offset);
- return Offset;
-}
-
-void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD,
- bool IsVirtualBase) {
- // Layout the base.
- uint64_t Offset = LayoutBase(RD);
-
- // Add base class offsets.
- if (IsVirtualBase)
- VBases.push_back(std::make_pair(RD, Offset));
- else
- Bases.push_back(std::make_pair(RD, Offset));
-}
-
void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
IsUnion = D->isUnion();
@@ -460,27 +487,17 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
// If this is a C++ class, lay out the vtable and the non-virtual bases.
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
- if (RD) {
- LayoutVtable(RD);
- // PrimaryBase goes first.
- if (PrimaryBase.getBase()) {
- if (PrimaryBase.isVirtual())
- IndirectPrimaryBases.insert(PrimaryBase.getBase());
- LayoutBaseNonVirtually(PrimaryBase.getBase(), PrimaryBase.isVirtual());
- }
+ if (RD)
LayoutNonVirtualBases(RD);
- }
LayoutFields(D);
NonVirtualSize = Size;
NonVirtualAlignment = Alignment;
- if (RD) {
- llvm::SmallSet<const CXXRecordDecl*, 32> mark;
- LayoutVirtualBases(RD, RD, PrimaryBase.getBase(),
- 0, mark, IndirectPrimaryBases);
- }
+ // If this is a C++ class, lay out its virtual bases.
+ if (RD)
+ LayoutVirtualBases(RD, 0, RD);
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
@@ -697,10 +714,7 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
NonVirtualSize,
Builder.NonVirtualAlignment,
Builder.PrimaryBase,
- Builder.Bases.data(),
- Builder.Bases.size(),
- Builder.VBases.data(),
- Builder.VBases.size());
+ Builder.Bases, Builder.VBases);
}
const ASTRecordLayout *
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index d4171d3cc9a9..a4bce753126a 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -56,21 +56,28 @@ class ASTRecordLayoutBuilder {
uint64_t NonVirtualSize;
unsigned NonVirtualAlignment;
+ /// PrimaryBase - the primary base class (if one exists) of the class
+ /// we're laying out.
ASTRecordLayout::PrimaryBaseInfo PrimaryBase;
- typedef llvm::SmallVector<std::pair<const CXXRecordDecl *,
- uint64_t>, 4> BaseOffsetsTy;
+ /// Bases - base classes and their offsets in the record.
+ ASTRecordLayout::BaseOffsetsMapTy Bases;
- /// Bases - base classes and their offsets from the record.
- BaseOffsetsTy Bases;
-
- // VBases - virtual base classes and their offsets from the record.
- BaseOffsetsTy VBases;
+ // VBases - virtual base classes and their offsets in the record.
+ ASTRecordLayout::BaseOffsetsMapTy VBases;
/// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
/// primary base classes for some other direct or indirect base class.
llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases;
+ /// FirstNearlyEmptyVBase - The first nearly empty virtual base class in
+ /// inheritance graph order. Used for determining the primary base class.
+ const CXXRecordDecl *FirstNearlyEmptyVBase;
+
+ /// VisitedVirtualBases - A set of all the visited virtual bases, used to
+ /// avoid visiting virtual bases more than once.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
+
/// EmptyClassOffsets - A map from offsets to empty record decls.
typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy;
EmptyClassOffsetsTy EmptyClassOffsets;
@@ -86,33 +93,35 @@ class ASTRecordLayoutBuilder {
void LayoutField(const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
- void SelectPrimaryBase(const CXXRecordDecl *RD);
- void SelectPrimaryVBase(const CXXRecordDecl *RD,
- const CXXRecordDecl *&FirstPrimary);
+ /// DeterminePrimaryBase - Determine the primary base of the given class.
+ void DeterminePrimaryBase(const CXXRecordDecl *RD);
+
+ void SelectPrimaryVBase(const CXXRecordDecl *RD);
/// IdentifyPrimaryBases - Identify all virtual base classes, direct or
/// indirect, that are primary base classes for some other direct or indirect
/// base class.
void IdentifyPrimaryBases(const CXXRecordDecl *RD);
- void setPrimaryBase(const CXXRecordDecl *Base, bool IsVirtual) {
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, IsVirtual);
- }
-
bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
+ /// LayoutNonVirtualBases - Determines the primary base class (if any) and
+ /// lays it out. Will then proceed to lay out all non-virtual base clasess.
+ void LayoutNonVirtualBases(const CXXRecordDecl *RD);
+
+ /// LayoutNonVirtualBase - Lays out a single non-virtual base.
+ void LayoutNonVirtualBase(const CXXRecordDecl *RD);
+
+ /// LayoutVirtualBases - Lays out all the virtual bases.
+ void LayoutVirtualBases(const CXXRecordDecl *RD, uint64_t Offset,
+ const CXXRecordDecl *MostDerivedClass);
+
+ /// LayoutVirtualBase - Lays out a single virtual base.
+ void LayoutVirtualBase(const CXXRecordDecl *RD);
+
/// LayoutBase - Will lay out a base and return the offset where it was
/// placed, in bits.
uint64_t LayoutBase(const CXXRecordDecl *RD);
-
- void LayoutVtable(const CXXRecordDecl *RD);
- void LayoutNonVirtualBases(const CXXRecordDecl *RD);
- void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase);
- void LayoutVirtualBase(const CXXRecordDecl *RD);
- void LayoutVirtualBases(const CXXRecordDecl *Class, const CXXRecordDecl *RD,
- const CXXRecordDecl *PB, uint64_t Offset,
- llvm::SmallSet<const CXXRecordDecl*, 32> &mark,
- llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary);
/// canPlaceRecordAtOffset - Return whether a record (either a base class
/// or a field) can be placed at the given offset.
@@ -134,9 +143,6 @@ class ASTRecordLayoutBuilder {
/// given offset.
void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset);
- /// getBaseOffset - Get the offset of a direct base class.
- uint64_t getBaseOffset(const CXXRecordDecl *Base);
-
/// FinishLayout - Finalize record layout. Adjust record size based on the
/// alignment.
void FinishLayout();
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 037bc14e7a91..09a61736d27e 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -474,7 +474,12 @@ void TypePrinter::PrintEnum(const EnumType *T, std::string &S) {
void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
Print(T->getUnderlyingType(), S);
- S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S;
+
+ // We don't actually make these in C, but the language options
+ // sometimes lie to us -- for example, if someone calls
+ // QualType::getAsString(). Just suppress the redundant tag if so.
+ if (Policy.LangOpts.CPlusPlus)
+ S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S;
}
void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T,
diff --git a/lib/Analysis/Makefile b/lib/Analysis/Makefile
index d6411122e322..9b473803fa92 100644
--- a/lib/Analysis/Makefile
+++ b/lib/Analysis/Makefile
@@ -15,7 +15,7 @@ LEVEL = ../../../..
LIBRARYNAME := clangAnalysis
BUILD_ARCHIVE = 1
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 16a61b7156fa..3da19ca16d5d 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -16,6 +16,7 @@
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
@@ -81,7 +82,7 @@ namespace {
/// enabled in the specified langauge, set to 1 if it is an extension
/// in the specified language, and set to 2 if disabled in the
/// specified language.
-static void AddKeyword(const char *Keyword, unsigned KWLen,
+static void AddKeyword(llvm::StringRef Keyword,
tok::TokenKind TokenCode, unsigned Flags,
const LangOptions &LangOpts, IdentifierTable &Table) {
unsigned AddResult = 0;
@@ -97,27 +98,27 @@ static void AddKeyword(const char *Keyword, unsigned KWLen,
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
- IdentifierInfo &Info = Table.get(Keyword, Keyword+KWLen);
+ IdentifierInfo &Info = Table.get(Keyword);
Info.setTokenID(TokenCode);
Info.setIsExtensionToken(AddResult == 1);
}
/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
/// representations.
-static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen,
+static void AddCXXOperatorKeyword(llvm::StringRef Keyword,
tok::TokenKind TokenCode,
IdentifierTable &Table) {
- IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen);
+ IdentifierInfo &Info = Table.get(Keyword);
Info.setTokenID(TokenCode);
Info.setIsCPlusPlusOperatorKeyword();
}
/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or
/// "property".
-static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID,
- const char *Name, unsigned NameLen,
+static void AddObjCKeyword(llvm::StringRef Name,
+ tok::ObjCKeywordKind ObjCID,
IdentifierTable &Table) {
- Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID);
+ Table.get(Name).setObjCKeywordID(ObjCID);
}
/// AddKeywords - Add all keywords to the symbol table.
@@ -125,20 +126,20 @@ static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID,
void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
// Add keywords and tokens for the current language.
#define KEYWORD(NAME, FLAGS) \
- AddKeyword(#NAME, strlen(#NAME), tok::kw_ ## NAME, \
+ AddKeyword(llvm::StringRef(#NAME), tok::kw_ ## NAME, \
FLAGS, LangOpts, *this);
#define ALIAS(NAME, TOK, FLAGS) \
- AddKeyword(NAME, strlen(NAME), tok::kw_ ## TOK, \
+ AddKeyword(llvm::StringRef(NAME), tok::kw_ ## TOK, \
FLAGS, LangOpts, *this);
#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
if (LangOpts.CXXOperatorNames) \
- AddCXXOperatorKeyword(#NAME, strlen(#NAME), tok::ALIAS, *this);
+ AddCXXOperatorKeyword(llvm::StringRef(#NAME), tok::ALIAS, *this);
#define OBJC1_AT_KEYWORD(NAME) \
if (LangOpts.ObjC1) \
- AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this);
+ AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this);
#define OBJC2_AT_KEYWORD(NAME) \
if (LangOpts.ObjC2) \
- AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this);
+ AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this);
#include "clang/Basic/TokenKinds.def"
}
@@ -388,12 +389,12 @@ const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
case OO_None:
case NUM_OVERLOADED_OPERATORS:
return 0;
-
+
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
case OO_##Name: return Spelling;
#include "clang/Basic/OperatorKinds.def"
}
-
+
return 0;
}
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index 578a4eb34bab..126d640364d0 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -115,9 +115,8 @@ const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const {
return SrcMgr->getBuffer(SrcMgr->getFileID(*this));
}
-std::pair<const char*, const char*> FullSourceLoc::getBufferData() const {
- const llvm::MemoryBuffer *Buf = getBuffer();
- return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd());
+llvm::StringRef FullSourceLoc::getBufferData() const {
+ return getBuffer()->getBuffer();
}
std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const {
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 0c22de7bddb1..4007ccf2a61e 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -13,12 +13,16 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include <algorithm>
+#include <string>
+#include <cstring>
+
using namespace clang;
using namespace SrcMgr;
using llvm::MemoryBuffer;
@@ -43,7 +47,8 @@ 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 ? Buffer->getBufferSize() : Entry->getSize();
+ return Buffer ? (unsigned) Buffer->getBufferSize()
+ : (unsigned) Entry->getSize();
}
void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
@@ -53,10 +58,17 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
Buffer = B;
}
-const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const {
+const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
+ bool *Invalid) const {
+ if (Invalid)
+ *Invalid = false;
+
// Lazily create the Buffer for ContentCaches that wrap files.
if (!Buffer && Entry) {
- Buffer = MemoryBuffer::getFile(Entry->getName(), ErrorStr,Entry->getSize());
+ std::string ErrorStr;
+ struct stat FileInfo;
+ Buffer = MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
+ Entry->getSize(), &FileInfo);
// 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
@@ -74,8 +86,27 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const {
char *Ptr = const_cast<char*>(Buffer->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;
+ }
}
}
+
return Buffer;
}
@@ -426,12 +457,11 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
}
const llvm::MemoryBuffer *
-SourceManager::getMemoryBufferForFile(const FileEntry *File) {
+SourceManager::getMemoryBufferForFile(const FileEntry *File,
+ bool *Invalid) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
- if (IR == 0)
- return 0;
-
- return IR->getBuffer();
+ assert(IR && "getOrCreateContentCache() cannot return NULL");
+ return IR->getBuffer(Diag, Invalid);
}
bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
@@ -444,15 +474,19 @@ bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
return false;
}
-/// getBufferData - Return a pointer to the start and end of the source buffer
-/// data for the specified FileID.
-std::pair<const char*, const char*>
-SourceManager::getBufferData(FileID FID) const {
+llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
+ if (Invalid)
+ *Invalid = false;
+
const llvm::MemoryBuffer *Buf = getBuffer(FID);
- return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd());
+ if (!Buf) {
+ if (*Invalid)
+ *Invalid = true;
+ return "";
+ }
+ return Buf->getBuffer();
}
-
//===----------------------------------------------------------------------===//
// SourceLocation manipulation methods.
//===----------------------------------------------------------------------===//
@@ -666,21 +700,34 @@ SourceManager::getInstantiationRange(SourceLocation Loc) const {
/// getCharacterData - Return a pointer to the start of the specified location
/// in the appropriate MemoryBuffer.
-const char *SourceManager::getCharacterData(SourceLocation SL) const {
+const char *SourceManager::getCharacterData(SourceLocation SL,
+ bool *Invalid) const {
// Note that this is a hot function in the getSpelling() path, which is
// heavily used by -E mode.
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL);
// Note that calling 'getBuffer()' may lazily page in a source file.
- return getSLocEntry(LocInfo.first).getFile().getContentCache()
- ->getBuffer()->getBufferStart() + LocInfo.second;
+ bool CharDataInvalid = false;
+ const llvm::MemoryBuffer *Buffer
+ = getSLocEntry(LocInfo.first).getFile().getContentCache()->getBuffer(Diag,
+ &CharDataInvalid);
+ if (Invalid)
+ *Invalid = CharDataInvalid;
+ return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
}
/// getColumnNumber - Return the column # for the specified file position.
/// this is significantly cheaper to compute than the line number.
-unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos) const {
- const char *Buf = getBuffer(FID)->getBufferStart();
+unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
+ bool *Invalid) const {
+ bool MyInvalid = false;
+ const char *Buf = getBuffer(FID, &MyInvalid)->getBufferStart();
+ if (Invalid)
+ *Invalid = MyInvalid;
+
+ if (MyInvalid)
+ return 1;
unsigned LineStart = FilePos;
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
@@ -688,25 +735,30 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos) const {
return FilePos-LineStart+1;
}
-unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc) const {
+unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
- return getColumnNumber(LocInfo.first, LocInfo.second);
+ return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
-unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const {
+unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- return getColumnNumber(LocInfo.first, LocInfo.second);
+ return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
-
-
-static DISABLE_INLINE void ComputeLineNumbers(ContentCache* FI,
- llvm::BumpPtrAllocator &Alloc);
-static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){
+static DISABLE_INLINE void ComputeLineNumbers(Diagnostic &Diag,
+ ContentCache* FI,
+ llvm::BumpPtrAllocator &Alloc,
+ bool &Invalid);
+static void ComputeLineNumbers(Diagnostic &Diag, ContentCache* FI,
+ llvm::BumpPtrAllocator &Alloc, bool &Invalid) {
// Note that calling 'getBuffer()' may lazily page in the file.
- const MemoryBuffer *Buffer = FI->getBuffer();
+ const MemoryBuffer *Buffer = FI->getBuffer(Diag, &Invalid);
+ if (Invalid)
+ return;
// Find the file offsets of all of the *physical* source lines. This does
// not look at trigraphs, escaped newlines, or anything else tricky.
@@ -752,7 +804,8 @@ static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){
/// for the position indicated. This requires building and caching a table of
/// line offsets for the MemoryBuffer, so this is not cheap: use only when
/// about to emit a diagnostic.
-unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
+unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
+ bool *Invalid) const {
ContentCache *Content;
if (LastLineNoFileIDQuery == FID)
Content = LastLineNoContentCache;
@@ -762,8 +815,15 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
// If this is the first use of line information for this buffer, compute the
/// SourceLineCache for it on demand.
- if (Content->SourceLineCache == 0)
- ComputeLineNumbers(Content, ContentCacheAlloc);
+ if (Content->SourceLineCache == 0) {
+ bool MyInvalid = false;
+ ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid);
+ if (Invalid)
+ *Invalid = MyInvalid;
+ if (MyInvalid)
+ return 1;
+ } else if (Invalid)
+ *Invalid = false;
// Okay, we know we have a line number table. Do a binary search to find the
// line number that this character position lands on.
@@ -849,12 +909,14 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
return LineNo;
}
-unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc) const {
+unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
}
-unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc) const {
+unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
@@ -894,10 +956,11 @@ SourceManager::getFileCharacteristic(SourceLocation Loc) const {
/// Return the filename or buffer identifier of the buffer the location is in.
/// Note that this name does not respect #line directives. Use getPresumedLoc
/// for normal clients.
-const char *SourceManager::getBufferName(SourceLocation Loc) const {
+const char *SourceManager::getBufferName(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return "<invalid loc>";
- return getBuffer(getFileID(Loc))->getBufferIdentifier();
+ return getBuffer(getFileID(Loc), Invalid)->getBufferIdentifier();
}
@@ -921,7 +984,7 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// before the MemBuffer as this will avoid unnecessarily paging in the
// MemBuffer.
const char *Filename =
- C->Entry ? C->Entry->getName() : C->getBuffer()->getBufferIdentifier();
+ C->Entry ? C->Entry->getName() : C->getBuffer(Diag)->getBufferIdentifier();
unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second);
unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second);
SourceLocation IncludeLoc = FI.getIncludeLoc();
@@ -977,8 +1040,12 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
// If this is the first use of line information for this buffer, compute the
/// SourceLineCache for it on demand.
- if (Content->SourceLineCache == 0)
- ComputeLineNumbers(Content, ContentCacheAlloc);
+ if (Content->SourceLineCache == 0) {
+ bool MyInvalid = false;
+ ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid);
+ if (MyInvalid)
+ return SourceLocation();
+ }
// Find the first file ID that corresponds to the given file.
FileID FirstFID;
@@ -1007,15 +1074,15 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
return SourceLocation();
if (Line > Content->NumLines) {
- unsigned Size = Content->getBuffer()->getBufferSize();
+ unsigned Size = Content->getBuffer(Diag)->getBufferSize();
if (Size > 0)
--Size;
return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size);
}
unsigned FilePos = Content->SourceLineCache[Line - 1];
- const char *Buf = Content->getBuffer()->getBufferStart() + FilePos;
- unsigned BufLength = Content->getBuffer()->getBufferEnd() - Buf;
+ const char *Buf = Content->getBuffer(Diag)->getBufferStart() + FilePos;
+ unsigned BufLength = Content->getBuffer(Diag)->getBufferEnd() - Buf;
unsigned i = 0;
// Check that the given column is valid.
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 3b226d0cdc52..8f472b3d3d45 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -935,6 +935,7 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
.Case("sse42", SSE42)
.Case("sse41", SSE41)
.Case("ssse3", SSSE3)
+ .Case("sse3", SSE3)
.Case("sse2", SSE2)
.Case("sse", SSE1)
.Case("mmx", MMX)
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index 130d805bb8aa..e64ba9446d89 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManager.h"
@@ -2335,7 +2336,11 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet Tmp;
if (InitEx) {
- if (VD->getType()->isReferenceType())
+ if (const CXXConstructExpr *E = dyn_cast<CXXConstructExpr>(InitEx)) {
+ VisitCXXConstructExpr(E, GetState(Pred)->getLValue(VD,
+ Pred->getLocationContext()), Pred, Dst);
+ return;
+ } else if (VD->getType()->isReferenceType())
VisitLValue(InitEx, Pred, Tmp);
else
Visit(InitEx, Pred, Tmp);
@@ -2826,7 +2831,8 @@ void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst) {
// Get the this object region from StoreManager.
const MemRegion *R =
- ValMgr.getRegionManager().getCXXThisRegion(TE->getType(),
+ ValMgr.getRegionManager().getCXXThisRegion(
+ getContext().getCanonicalType(TE->getType()),
Pred->getLocationContext());
const GRState *state = GetState(Pred);
@@ -3126,6 +3132,78 @@ void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
}
}
+void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ const CXXConstructorDecl *CD = E->getConstructor();
+ assert(CD);
+
+ if (!CD->isThisDeclarationADefinition())
+ // FIXME: invalidate the object.
+ return;
+
+
+ // Evaluate other arguments.
+ CXXConstructExpr::arg_iterator AB
+ = const_cast<CXXConstructExpr*>(E)->arg_begin();
+ CXXConstructExpr::arg_iterator AE
+ = const_cast<CXXConstructExpr*>(E)->arg_end();
+ llvm::SmallVector<CallExprWLItem, 20> WorkList;
+ WorkList.reserve(AE - AB);
+ WorkList.push_back(CallExprWLItem(AB, Pred));
+ ExplodedNodeSet ArgsEvaluated;
+ const FunctionProtoType *Proto = CD->getType()->getAs<FunctionProtoType>();
+
+ while (!WorkList.empty()) {
+ CallExprWLItem Item = WorkList.back();
+ WorkList.pop_back();
+
+ if (Item.I == AE) {
+ ArgsEvaluated.insert(Item.N);
+ continue;
+ }
+
+ // Evaluate the argument.
+ ExplodedNodeSet Tmp;
+ const unsigned ParamIdx = Item.I - AB;
+
+ bool VisitAsLvalue = false;
+
+ if (ParamIdx < Proto->getNumArgs())
+ VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
+
+ if (VisitAsLvalue)
+ VisitLValue(*Item.I, Item.N, Tmp);
+ else
+ Visit(*Item.I, Item.N, Tmp);
+
+ ++(Item.I);
+
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+ WorkList.push_back(CallExprWLItem(Item.I, *NI));
+ }
+ // The callee stack frame context used to create the 'this' parameter region.
+ const StackFrameContext *SFC = AMgr.getStackFrame(CD,
+ Pred->getLocationContext(),
+ E, Builder->getBlock(), Builder->getIndex());
+
+ Type *T = CD->getParent()->getTypeForDecl();
+ QualType PT = getContext().getPointerType(QualType(T,0));
+ const CXXThisRegion *ThisR = ValMgr.getRegionManager().getCXXThisRegion(PT,
+ SFC);
+
+ CallEnter Loc(E, CD, Pred->getLocationContext());
+ for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
+ NE = ArgsEvaluated.end(); NI != NE; ++NI) {
+ const GRState *state = GetState(*NI);
+ // Setup 'this' region.
+ state = state->bindLoc(loc::MemRegionVal(ThisR), Dest);
+ ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
+ if (N)
+ Dst.Add(N);
+ }
+}
//===----------------------------------------------------------------------===//
// Checker registration/lookup.
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/Makefile b/lib/Checker/Makefile
index 673d152270ca..c45ab294dec4 100644
--- a/lib/Checker/Makefile
+++ b/lib/Checker/Makefile
@@ -15,7 +15,7 @@ LEVEL = ../../../..
LIBRARYNAME := clangChecker
BUILD_ARCHIVE = 1
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index 91c3a15f4473..307ef7880388 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -22,6 +22,8 @@
#include "clang/Analysis/Support/Optional.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableList.h"
@@ -29,8 +31,6 @@
using namespace clang;
-#define USE_EXPLICIT_COMPOUND 0
-
//===----------------------------------------------------------------------===//
// Representation of binding keys.
//===----------------------------------------------------------------------===//
@@ -1336,54 +1336,13 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
QualType T = R->getValueType(getContext());
assert(T->isStructureType());
-
- const RecordType* RT = T->getAsStructureType();
- RecordDecl* RD = RT->getDecl();
- assert(RD->isDefinition());
- (void)RD;
-#if USE_EXPLICIT_COMPOUND
- llvm::ImmutableList<SVal> StructVal = getBasicVals().getEmptySValList();
-
- // FIXME: We shouldn't use a std::vector. If RecordDecl doesn't have a
- // reverse iterator, we should implement one.
- std::vector<FieldDecl *> Fields(RD->field_begin(), RD->field_end());
-
- for (std::vector<FieldDecl *>::reverse_iterator Field = Fields.rbegin(),
- FieldEnd = Fields.rend();
- Field != FieldEnd; ++Field) {
- FieldRegion* FR = MRMgr.getFieldRegion(*Field, R);
- QualType FTy = (*Field)->getType();
- SVal FieldValue = Retrieve(store, loc::MemRegionVal(FR), FTy).getSVal();
- StructVal = getBasicVals().consVals(FieldValue, StructVal);
- }
-
- return ValMgr.makeCompoundVal(T, StructVal);
-#else
+ assert(T->getAsStructureType()->getDecl()->isDefinition());
return ValMgr.makeLazyCompoundVal(store, R);
-#endif
}
SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) {
-#if USE_EXPLICIT_COMPOUND
- QualType T = R->getValueType(getContext());
- ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
-
- llvm::ImmutableList<SVal> ArrayVal = getBasicVals().getEmptySValList();
- uint64_t size = CAT->getSize().getZExtValue();
- for (uint64_t i = 0; i < size; ++i) {
- SVal Idx = ValMgr.makeArrayIndex(i);
- ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R,
- getContext());
- QualType ETy = ER->getElementType();
- SVal ElementVal = Retrieve(store, loc::MemRegionVal(ER), ETy).getSVal();
- ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal);
- }
-
- return ValMgr.makeCompoundVal(T, ArrayVal);
-#else
assert(isa<ConstantArrayType>(R->getValueType(getContext())));
return ValMgr.makeLazyCompoundVal(store, R);
-#endif
}
//===----------------------------------------------------------------------===//
@@ -1884,18 +1843,29 @@ Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
StackFrameContext const *frame) {
FunctionDecl const *FD = cast<FunctionDecl>(frame->getDecl());
- CallExpr const *CE = cast<CallExpr>(frame->getCallSite());
-
FunctionDecl::param_const_iterator PI = FD->param_begin();
+ Store store = state->getStore();
- CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
+ if (CallExpr const *CE = dyn_cast<CallExpr>(frame->getCallSite())) {
+ CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
- // Copy the arg expression value to the arg variables.
- Store store = state->getStore();
- for (; AI != AE; ++AI, ++PI) {
- SVal ArgVal = state->getSVal(*AI);
- store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal);
- }
+ // Copy the arg expression value to the arg variables.
+ for (; AI != AE; ++AI, ++PI) {
+ SVal ArgVal = state->getSVal(*AI);
+ store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI,frame)),ArgVal);
+ }
+ } else if (const CXXConstructExpr *CE =
+ dyn_cast<CXXConstructExpr>(frame->getCallSite())) {
+ CXXConstructExpr::const_arg_iterator AI = CE->arg_begin(),
+ AE = CE->arg_end();
+
+ // Copy the arg expression value to the arg variables.
+ for (; AI != AE; ++AI, ++PI) {
+ SVal ArgVal = state->getSVal(*AI);
+ store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI,frame)),ArgVal);
+ }
+ } else
+ assert(0 && "Unhandled call expression.");
return state->makeWithStore(store);
}
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 99c6dfd7ebc4..525e85841646 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -98,7 +98,7 @@ CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
}
if (VBase)
VirtualOffset =
- getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
+ getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
uint64_t Offset =
ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
@@ -1540,11 +1540,11 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
Int8PtrTy->getPointerTo());
VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
- int64_t VBaseOffsetIndex =
- CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
+ int64_t VBaseOffsetOffset =
+ CGM.getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
llvm::Value *VBaseOffsetPtr =
- Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr");
+ Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset, "vbase.offset.ptr");
const llvm::Type *PtrDiffTy =
ConvertType(getContext().getPointerDiffType());
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index c3302e661dfb..60aa4e784e6c 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -104,7 +104,10 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
void CGDebugInfo::CreateCompileUnit() {
// Get absolute path name.
- llvm::sys::Path AbsFileName(CGM.getCodeGenOpts().MainFileName);
+ std::string MainFileName = CGM.getCodeGenOpts().MainFileName;
+ if (MainFileName.empty())
+ MainFileName = "<unknown>";
+ llvm::sys::Path AbsFileName(MainFileName);
AbsFileName.makeAbsolute();
unsigned LangTag;
@@ -649,9 +652,9 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl());
if (BI->isVirtual()) {
- // virtual base offset index is -ve. The code generator emits dwarf
+ // virtual base offset offset is -ve. The code generator emits dwarf
// expression where it expects +ve number.
- BaseOffset = 0 - CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base);
+ BaseOffset = 0 - CGM.getVtableInfo().getVirtualBaseOffsetOffset(RD, Base);
BFlags = llvm::DIType::FlagVirtual;
} else
BaseOffset = RL.getBaseClassOffset(Base);
@@ -774,9 +777,8 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// A RD->getName() is not unique. However, the debug info descriptors
// are uniqued so use type name to ensure uniquness.
- llvm::SmallString<256> FwdDeclName;
- FwdDeclName.resize(256);
- sprintf(&FwdDeclName[0], "fwd.type.%d", FwdDeclCount++);
+ llvm::SmallString<128> FwdDeclName;
+ llvm::raw_svector_ostream(FwdDeclName) << "fwd.type." << FwdDeclCount++;
llvm::DIDescriptor FDContext =
getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit);
llvm::DICompositeType FwdDecl =
@@ -792,6 +794,9 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// Otherwise, insert it into the TypeCache so that recursive uses will find
// it.
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
+ // Push the struct on region stack.
+ RegionStack.push_back(FwdDecl.getNode());
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl.getNode());
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
@@ -822,6 +827,12 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+ RegionStack.pop_back();
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI =
+ RegionMap.find(Ty->getDecl());
+ if (RI != RegionMap.end())
+ RegionMap.erase(RI);
+
llvm::DIDescriptor RDContext =
getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit);
llvm::DICompositeType RealDecl =
@@ -834,7 +845,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl);
-
+ RegionMap[RD] = llvm::WeakVH(RealDecl.getNode());
return RealDecl;
}
@@ -874,6 +885,9 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Otherwise, insert it into the TypeCache so that recursive uses will find
// it.
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
+ // Push the struct on region stack.
+ RegionStack.push_back(FwdDecl.getNode());
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl.getNode());
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
@@ -946,6 +960,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIArray Elements =
DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+ RegionStack.pop_back();
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI =
+ RegionMap.find(Ty->getDecl());
+ if (RI != RegionMap.end())
+ RegionMap.erase(RI);
+
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
@@ -958,6 +978,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl);
+ RegionMap[ID] = llvm::WeakVH(RealDecl.getNode());
return RealDecl;
}
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 793a22050677..1dc083f387ba 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -211,6 +211,8 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D,
if (D.getInit())
GV = AddInitializerToGlobalBlockVarDecl(D, GV);
+ GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
+
// FIXME: Merge attribute handling.
if (const AnnotateAttr *AA = D.getAttr<AnnotateAttr>()) {
SourceManager &SM = CGM.getContext().getSourceManager();
@@ -471,68 +473,6 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
EnsureInsertPoint();
}
- if (Init) {
- llvm::Value *Loc = DeclPtr;
- if (isByRef)
- Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
- D.getNameAsString());
-
- bool isVolatile =
- getContext().getCanonicalType(D.getType()).isVolatileQualified();
-
- // If the initializer was a simple constant initializer, we can optimize it
- // in various ways.
- if (IsSimpleConstantInitializer) {
- llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this);
- assert(Init != 0 && "Wasn't a simple constant init?");
-
- llvm::Value *AlignVal =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- Align.getQuantity());
- const llvm::Type *IntPtr =
- llvm::IntegerType::get(VMContext, LLVMPointerWidth);
- llvm::Value *SizeVal =
- llvm::ConstantInt::get(IntPtr,
- getContext().getTypeSizeInChars(Ty).getQuantity());
-
- const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
- if (Loc->getType() != BP)
- Loc = Builder.CreateBitCast(Loc, BP, "tmp");
-
- // If the initializer is all zeros, codegen with memset.
- if (isa<llvm::ConstantAggregateZero>(Init)) {
- llvm::Value *Zero =
- llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0);
- Builder.CreateCall4(CGM.getMemSetFn(), Loc, Zero, SizeVal, AlignVal);
- } else {
- // Otherwise, create a temporary global with the initializer then
- // memcpy from the global to the alloca.
- std::string Name = GetStaticDeclName(*this, D, ".");
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true,
- llvm::GlobalValue::InternalLinkage,
- Init, Name, 0, false, 0);
- GV->setAlignment(Align.getQuantity());
-
- llvm::Value *SrcPtr = GV;
- if (SrcPtr->getType() != BP)
- SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
-
- Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal);
- }
- } else if (Ty->isReferenceType()) {
- RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true);
- EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty);
- } else if (!hasAggregateLLVMType(Init->getType())) {
- llvm::Value *V = EmitScalarExpr(Init);
- EmitStoreOfScalar(V, Loc, isVolatile, D.getType());
- } else if (Init->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(Init, Loc, isVolatile);
- } else {
- EmitAggExpr(Init, Loc, isVolatile);
- }
- }
-
if (isByRef) {
const llvm::PointerType *PtrToInt8Ty = llvm::Type::getInt8PtrTy(VMContext);
@@ -591,6 +531,68 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
}
}
+ if (Init) {
+ llvm::Value *Loc = DeclPtr;
+ if (isByRef)
+ Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
+ D.getNameAsString());
+
+ bool isVolatile =
+ getContext().getCanonicalType(D.getType()).isVolatileQualified();
+
+ // If the initializer was a simple constant initializer, we can optimize it
+ // in various ways.
+ if (IsSimpleConstantInitializer) {
+ llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this);
+ assert(Init != 0 && "Wasn't a simple constant init?");
+
+ llvm::Value *AlignVal =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ Align.getQuantity());
+ const llvm::Type *IntPtr =
+ llvm::IntegerType::get(VMContext, LLVMPointerWidth);
+ llvm::Value *SizeVal =
+ llvm::ConstantInt::get(IntPtr,
+ getContext().getTypeSizeInChars(Ty).getQuantity());
+
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
+ if (Loc->getType() != BP)
+ Loc = Builder.CreateBitCast(Loc, BP, "tmp");
+
+ // If the initializer is all zeros, codegen with memset.
+ if (isa<llvm::ConstantAggregateZero>(Init)) {
+ llvm::Value *Zero =
+ llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0);
+ Builder.CreateCall4(CGM.getMemSetFn(), Loc, Zero, SizeVal, AlignVal);
+ } else {
+ // Otherwise, create a temporary global with the initializer then
+ // memcpy from the global to the alloca.
+ std::string Name = GetStaticDeclName(*this, D, ".");
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ Init, Name, 0, false, 0);
+ GV->setAlignment(Align.getQuantity());
+
+ llvm::Value *SrcPtr = GV;
+ if (SrcPtr->getType() != BP)
+ SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
+
+ Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal);
+ }
+ } else if (Ty->isReferenceType()) {
+ RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true);
+ EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty);
+ } else if (!hasAggregateLLVMType(Init->getType())) {
+ llvm::Value *V = EmitScalarExpr(Init);
+ EmitStoreOfScalar(V, Loc, isVolatile, D.getType());
+ } else if (Init->getType()->isAnyComplexType()) {
+ EmitComplexExprIntoAddr(Init, Loc, isVolatile);
+ } else {
+ EmitAggExpr(Init, Loc, isVolatile);
+ }
+ }
+
// Handle CXX destruction of variables.
QualType DtorTy(Ty);
while (const ArrayType *Array = getContext().getAsArrayType(DtorTy))
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 198e2d12fca3..243635744ffb 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -1147,8 +1147,8 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
// Collect the names of referenced protocols
llvm::SmallVector<std::string, 16> Protocols;
- const ObjCInterfaceDecl *ClassDecl = OCD->getClassInterface();
- const ObjCList<ObjCProtocolDecl> &Protos =ClassDecl->getReferencedProtocols();
+ const ObjCCategoryDecl *CatDecl = OCD->getCategoryDecl();
+ const ObjCList<ObjCProtocolDecl> &Protos = CatDecl->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(),
E = Protos.end(); I != E; ++I)
Protocols.push_back((*I)->getNameAsString());
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 5236d2063489..4907223fe346 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -760,7 +760,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
// subobject. For a virtual base, this is the offset in the virtual table of
// the virtual base offset for the virtual base referenced (negative).
if (Base->isVirtual())
- OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, BaseDecl);
+ OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetOffset(RD, BaseDecl);
else {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
OffsetFlags = Layout.getBaseClassOffset(BaseDecl) / 8;
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 4500ec033cd8..9bcf986af842 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -63,10 +63,7 @@ public:
/// Offset - the base offset of the overrider in the layout class.
uint64_t Offset;
- /// OldOffset - FIXME: Remove this.
- int64_t OldOffset;
-
- OverriderInfo() : Method(0), Offset(0), OldOffset(0) { }
+ OverriderInfo() : Method(0), Offset(0) { }
};
private:
@@ -251,7 +248,6 @@ void FinalOverriders::AddOverriders(BaseSubobject Base,
OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)];
assert(!Overrider.Method && "Overrider should not exist yet!");
- Overrider.OldOffset = Base.getBaseOffset();
Overrider.Offset = OffsetInLayoutClass;
Overrider.Method = MD;
}
@@ -415,7 +411,6 @@ void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD,
// Set the new overrider.
Overrider.Offset = OverriderOffsetInLayoutClass;
- Overrider.OldOffset = NewBase.getBaseOffset();
Overrider.Method = NewMD;
// And propagate it further.
@@ -559,7 +554,7 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) {
Out << " " << MD->getQualifiedNameAsString() << " - (";
Out << Overrider.Method->getQualifiedNameAsString();
- Out << ", " << Overrider.OldOffset / 8 << ", " << Overrider.Offset / 8 << ')';
+ Out << ", " << ", " << Overrider.Offset / 8 << ')';
AdjustmentOffsetsMapTy::const_iterator AI =
ReturnAdjustments.find(std::make_pair(Base, MD));
@@ -834,6 +829,11 @@ int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) {
/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets.
class VCallAndVBaseOffsetBuilder {
+public:
+ typedef llvm::DenseMap<const CXXRecordDecl *, int64_t>
+ VBaseOffsetOffsetsMapTy;
+
+private:
/// MostDerivedClass - The most derived class for which we're building vcall
/// and vbase offsets.
const CXXRecordDecl *MostDerivedClass;
@@ -856,6 +856,11 @@ class VCallAndVBaseOffsetBuilder {
/// VCallOffsets - Keeps track of vcall offsets.
VCallOffsetMap VCallOffsets;
+
+ /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets,
+ /// relative to the address point.
+ VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
+
/// FinalOverriders - The final overriders of the most derived class.
/// (Can be null when we're not building a vtable of the most derived class).
const FinalOverriders *Overriders;
@@ -871,6 +876,10 @@ class VCallAndVBaseOffsetBuilder {
/// AddVBaseOffsets - Add vbase offsets for the given class.
void AddVBaseOffsets(const CXXRecordDecl *Base, uint64_t OffsetInLayoutClass);
+ /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in
+ /// bytes, relative to the vtable address point.
+ int64_t getCurrentOffsetOffset() const;
+
public:
VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass,
const CXXRecordDecl *LayoutClass,
@@ -889,7 +898,10 @@ public:
const_iterator components_begin() const { return Components.rbegin(); }
const_iterator components_end() const { return Components.rend(); }
- const VCallOffsetMap& getVCallOffsets() const { return VCallOffsets; }
+ const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; }
+ const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
+ return VBaseOffsetOffsets;
+ }
};
void
@@ -940,6 +952,20 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
AddVCallOffsets(Base, RealBaseOffset);
}
+int64_t VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
+ // OffsetIndex is the index of this vcall or vbase offset, relative to the
+ // vtable address point. (We subtract 3 to account for the information just
+ // above the address point, the RTTI info, the offset to top, and the
+ // vcall offset itself).
+ int64_t OffsetIndex = -(int64_t)(3 + Components.size());
+
+ // FIXME: We shouldn't use / 8 here.
+ int64_t OffsetOffset = OffsetIndex *
+ (int64_t)Context.Target.getPointerWidth(0) / 8;
+
+ return OffsetOffset;
+}
+
void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
uint64_t VBaseOffset) {
const CXXRecordDecl *RD = Base.getBase();
@@ -980,15 +1006,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
if (!MD->isVirtual())
continue;
- // OffsetIndex is the index of this vcall offset, relative to the vtable
- // address point. (We subtract 3 to account for the information just
- // above the address point, the RTTI info, the offset to top, and the
- // vcall offset itself).
- int64_t OffsetIndex = -(int64_t)(3 + Components.size());
-
- // FIXME: We shouldn't use / 8 here.
- int64_t OffsetOffset = OffsetIndex *
- (int64_t)Context.Target.getPointerWidth(0) / 8;
+ int64_t OffsetOffset = getCurrentOffsetOffset();
// Don't add a vcall offset if we already have one for this member function
// signature.
@@ -1048,10 +1066,17 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
int64_t Offset =
(int64_t)(LayoutClassLayout.getVBaseClassOffset(BaseDecl) -
OffsetInLayoutClass) / 8;
-
+
+ // Add the vbase offset offset.
+ assert(!VBaseOffsetOffsets.count(BaseDecl) &&
+ "vbase offset offset already exists!");
+
+ int64_t VBaseOffsetOffset = getCurrentOffsetOffset();
+ VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset));
+
Components.push_back(VtableComponent::MakeVBaseOffset(Offset));
}
-
+
// Check the base class looking for more vbase offsets.
AddVBaseOffsets(BaseDecl, OffsetInLayoutClass);
}
@@ -1096,6 +1121,13 @@ private:
/// bases in this vtable.
llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
+ typedef llvm::DenseMap<const CXXRecordDecl *, int64_t>
+ VBaseOffsetOffsetsMapTy;
+
+ /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for
+ /// the most derived class.
+ VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
+
/// Components - The components of the vtable being built.
llvm::SmallVector<VtableComponent, 64> Components;
@@ -1117,24 +1149,27 @@ private:
bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
};
- /// ReturnAdjustments - The return adjustments needed in this vtable.
- llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16>
- ReturnAdjustments;
-
/// MethodInfo - Contains information about a method in a vtable.
/// (Used for computing 'this' pointer adjustment thunks.
struct MethodInfo {
/// BaseOffset - The base offset of this method.
const uint64_t BaseOffset;
+ /// BaseOffsetInLayoutClass - The base offset in the layout class of this
+ /// method.
+ const uint64_t BaseOffsetInLayoutClass;
+
/// VtableIndex - The index in the vtable that this method has.
/// (For destructors, this is the index of the complete destructor).
const uint64_t VtableIndex;
- MethodInfo(uint64_t BaseOffset, uint64_t VtableIndex)
- : BaseOffset(BaseOffset), VtableIndex(VtableIndex) { }
+ MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass,
+ uint64_t VtableIndex)
+ : BaseOffset(BaseOffset),
+ BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
+ VtableIndex(VtableIndex) { }
- MethodInfo() : BaseOffset(0), VtableIndex(0) { }
+ MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VtableIndex(0) { }
};
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
@@ -1158,9 +1193,27 @@ private:
bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; }
};
- /// ThisAdjustments - The 'this' pointer adjustments needed in this vtable.
- llvm::SmallVector<std::pair<uint64_t, ThisAdjustment>, 16>
- ThisAdjustments;
+ /// ThunkInfo - The 'this' pointer adjustment as well as an optional return
+ /// adjustment for a thunk.
+ struct ThunkInfo {
+ /// This - The 'this' pointer adjustment.
+ ThisAdjustment This;
+
+ /// Return - The return adjustment.
+ ReturnAdjustment Return;
+
+ ThunkInfo() { }
+
+ ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
+ : This(This), Return(Return) { }
+
+ bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
+ };
+
+ typedef llvm::DenseMap<uint64_t, ThunkInfo> ThunksInfoMapTy;
+
+ /// Thunks - The thunks by vtable index in the vtable currently being built.
+ ThunksInfoMapTy Thunks;
/// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
/// part of the vtable we're currently building.
@@ -1182,11 +1235,13 @@ private:
BaseSubobject Derived) const;
/// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the
- /// given virtual member function and the 'this' pointer adjustment base
- /// offset.
- ThisAdjustment ComputeThisAdjustment(const CXXMethodDecl *MD,
- BaseOffset Offset);
-
+ /// given virtual member function, its offset in the layout class and its
+ /// final overrider.
+ ThisAdjustment
+ ComputeThisAdjustment(const CXXMethodDecl *MD,
+ uint64_t BaseOffsetInLayoutClass,
+ FinalOverriders::OverriderInfo Overrider);
+
/// AddMethod - Add a single virtual member function to the vtable
/// components vector.
void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
@@ -1235,7 +1290,11 @@ private:
/// LayoutSecondaryVtables - Layout the secondary vtables for the given base
/// subobject.
- void LayoutSecondaryVtables(BaseSubobject Base, uint64_t OffsetInLayoutClass);
+ ///
+ /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
+ /// or a direct or indirect base of a virtual base.
+ void LayoutSecondaryVtables(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ uint64_t OffsetInLayoutClass);
/// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this
/// class hierarchy.
@@ -1292,8 +1351,6 @@ OverridesMethodInBases(const CXXMethodDecl *MD,
}
void VtableBuilder::ComputeThisAdjustments() {
- std::map<uint64_t, ThisAdjustment> SortedThisAdjustments;
-
// Now go through the method info map and see if any of the methods need
// 'this' pointer adjustments.
for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
@@ -1301,56 +1358,34 @@ void VtableBuilder::ComputeThisAdjustments() {
const CXXMethodDecl *MD = I->first;
const MethodInfo &MethodInfo = I->second;
- BaseSubobject OverriddenBaseSubobject(MD->getParent(),
- MethodInfo.BaseOffset);
-
- // Get the final overrider for this method.
- FinalOverriders::OverriderInfo Overrider =
- Overriders.getOverrider(OverriddenBaseSubobject, MD);
-
- // Check if we need an adjustment.
- if (Overrider.OldOffset == (int64_t)MethodInfo.BaseOffset)
- continue;
-
- uint64_t VtableIndex = MethodInfo.VtableIndex;
-
- // Ignore adjustments for pure virtual member functions.
- if (Overrider.Method->isPure())
- continue;
-
// Ignore adjustments for unused function pointers.
+ uint64_t VtableIndex = MethodInfo.VtableIndex;
if (Components[VtableIndex].getKind() ==
VtableComponent::CK_UnusedFunctionPointer)
continue;
+
+ // Get the final overrider for this method.
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders.getOverrider(BaseSubobject(MD->getParent(),
+ MethodInfo.BaseOffset), MD);
+
+ ThisAdjustment ThisAdjustment =
+ ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
- BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
- Overrider.OldOffset);
-
- // Compute the adjustment offset.
- BaseOffset ThisAdjustmentOffset =
- ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
- OverriderBaseSubobject);
-
- // Then compute the adjustment itself.
- ThisAdjustment ThisAdjustment = ComputeThisAdjustment(Overrider.Method,
- ThisAdjustmentOffset);
+ if (ThisAdjustment.isEmpty())
+ continue;
// Add it.
- SortedThisAdjustments.insert(std::make_pair(VtableIndex, ThisAdjustment));
-
+ Thunks[VtableIndex].This = ThisAdjustment;
+
if (isa<CXXDestructorDecl>(MD)) {
// Add an adjustment for the deleting destructor as well.
- SortedThisAdjustments.insert(std::make_pair(VtableIndex + 1,
- ThisAdjustment));
+ Thunks[VtableIndex + 1].This = ThisAdjustment;
}
}
/// Clear the method info map.
MethodInfoMap.clear();
-
- // Add the sorted elements.
- ThisAdjustments.append(SortedThisAdjustments.begin(),
- SortedThisAdjustments.end());
}
VtableBuilder::ReturnAdjustment
@@ -1360,13 +1395,20 @@ VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
if (!Offset.isEmpty()) {
if (Offset.VirtualBase) {
// Get the virtual base offset offset.
- Adjustment.VBaseOffsetOffset =
- VtableInfo.getVirtualBaseOffsetIndex(Offset.DerivedClass,
- Offset.VirtualBase);
- // FIXME: Once the assert in getVirtualBaseOffsetIndex is back again,
+ if (Offset.DerivedClass == MostDerivedClass) {
+ // We can get the offset offset directly from our map.
+ Adjustment.VBaseOffsetOffset =
+ VBaseOffsetOffsets.lookup(Offset.VirtualBase);
+ } else {
+ Adjustment.VBaseOffsetOffset =
+ VtableInfo.getVirtualBaseOffsetOffset(Offset.DerivedClass,
+ Offset.VirtualBase);
+ }
+
+ // FIXME: Once the assert in getVirtualBaseOffsetOffset is back again,
// we can get rid of this assert.
assert(Adjustment.VBaseOffsetOffset != 0 &&
- "Invalid base offset offset!");
+ "Invalid vbase offset offset!");
}
Adjustment.NonVirtual = Offset.NonVirtualOffset;
@@ -1402,13 +1444,13 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
if (Offset.VirtualBase) {
// If we have a virtual base class, the non-virtual offset is relative
// to the virtual base class offset.
- const ASTRecordLayout &MostDerivedClassLayout =
- Context.getASTRecordLayout(MostDerivedClass);
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
/// Get the virtual base offset, relative to the most derived class
/// layout.
OffsetToBaseSubobject +=
- MostDerivedClassLayout.getVBaseClassOffset(Offset.VirtualBase);
+ LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase);
} else {
// Otherwise, the non-virtual offset is relative to the derived class
// offset.
@@ -1427,38 +1469,57 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
return BaseOffset();
}
+VtableBuilder::ThisAdjustment
+VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
+ uint64_t BaseOffsetInLayoutClass,
+ FinalOverriders::OverriderInfo Overrider) {
+ // Check if we need an adjustment at all.
+ if (BaseOffsetInLayoutClass == Overrider.Offset)
+ return ThisAdjustment();
+
+ // Ignore adjustments for pure virtual member functions.
+ if (Overrider.Method->isPure())
+ return ThisAdjustment();
+
+ BaseSubobject OverriddenBaseSubobject(MD->getParent(),
+ BaseOffsetInLayoutClass);
+
+ BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
+ Overrider.Offset);
+
+ // Compute the adjustment offset.
+ BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
+ OverriderBaseSubobject);
+ if (Offset.isEmpty())
+ return ThisAdjustment();
-VtableBuilder::ThisAdjustment
-VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
- BaseOffset Offset) {
ThisAdjustment Adjustment;
- if (!Offset.isEmpty()) {
- if (Offset.VirtualBase) {
- // Get the vcall offset map for this virtual base.
- VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase];
-
- if (VCallOffsets.empty()) {
- // We don't have vcall offsets for this virtual base, go ahead and
- // build them.
- VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass,
- /*FinalOverriders=*/0,
- BaseSubobject(Offset.VirtualBase, 0),
- /*BaseIsVirtual=*/true,
- /*OffsetInLayoutClass=*/0);
+ if (Offset.VirtualBase) {
+ // Get the vcall offset map for this virtual base.
+ VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase];
+
+ if (VCallOffsets.empty()) {
+ // We don't have vcall offsets for this virtual base, go ahead and
+ // build them.
+ VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass,
+ /*FinalOverriders=*/0,
+ BaseSubobject(Offset.VirtualBase, 0),
+ /*BaseIsVirtual=*/true,
+ /*OffsetInLayoutClass=*/0);
- VCallOffsets = Builder.getVCallOffsets();
- }
-
- Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD);
+ VCallOffsets = Builder.getVCallOffsets();
}
-
- Adjustment.NonVirtual = Offset.NonVirtualOffset;
+
+ Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD);
}
+
+ // Set the non-virtual part of the adjustment.
+ Adjustment.NonVirtual = Offset.NonVirtualOffset;
return Adjustment;
}
-
+
void
VtableBuilder::AddMethod(const CXXMethodDecl *MD,
ReturnAdjustment ReturnAdjustment) {
@@ -1472,8 +1533,7 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD,
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
- ReturnAdjustments.push_back(std::make_pair(Components.size(),
- ReturnAdjustment));
+ Thunks[Components.size()].Return = ReturnAdjustment;
// Add the function.
Components.push_back(VtableComponent::MakeFunction(MD));
@@ -1665,6 +1725,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
MethodInfo MethodInfo(Base.getBaseOffset(),
+ BaseOffsetInLayoutClass,
OverriddenMethodInfo.VtableIndex);
assert(!MethodInfoMap.count(MD) &&
@@ -1677,7 +1738,8 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
}
// Insert the method info for this method.
- MethodInfo MethodInfo(Base.getBaseOffset(), Components.size());
+ MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
+ Components.size());
assert(!MethodInfoMap.count(MD) &&
"Should not have method info for this method yet!");
@@ -1737,6 +1799,11 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
VCallOffsets = Builder.getVCallOffsets();
}
+ // If we're laying out the most derived class we want to keep track of the
+ // virtual base class offset offsets.
+ if (Base.getBase() == MostDerivedClass)
+ VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
+
// Add the offset to top.
// FIXME: We should not use / 8 here.
int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass -
@@ -1772,11 +1839,16 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint));
}
+ bool BaseIsMorallyVirtual = BaseIsVirtual;
+ if (isBuildingConstructorVtable() && Base.getBase() == MostDerivedClass)
+ BaseIsMorallyVirtual = false;
+
// Layout secondary vtables.
- LayoutSecondaryVtables(Base, OffsetInLayoutClass);
+ LayoutSecondaryVtables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
}
void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
uint64_t OffsetInLayoutClass) {
// Itanium C++ ABI 2.5.2:
// Following the primary virtual table of a derived class are secondary
@@ -1800,6 +1872,16 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base,
if (!BaseDecl->isDynamicClass())
continue;
+ if (isBuildingConstructorVtable()) {
+ // Itanium C++ ABI 2.6.4:
+ // Some of the base class subobjects may not need construction virtual
+ // tables, which will therefore not be present in the construction
+ // virtual table group, even though the subobject virtual tables are
+ // present in the main virtual table group for the complete object.
+ if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases())
+ continue;
+ }
+
// Get the base offset of this base.
uint64_t RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl);
uint64_t BaseOffset = Base.getBaseOffset() + RelativeBaseOffset;
@@ -1810,7 +1892,7 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base,
// to emit secondary vtables for other bases of this base.
if (BaseDecl == PrimaryBase) {
LayoutSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset),
- BaseOffsetInLayoutClass);
+ BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
continue;
}
@@ -1920,15 +2002,15 @@ VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
/// dumpLayout - Dump the vtable layout.
void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
- if (MostDerivedClass == LayoutClass) {
- Out << "Vtable for '";
- Out << MostDerivedClass->getQualifiedNameAsString();
- } else {
+ if (isBuildingConstructorVtable()) {
Out << "Construction vtable for ('";
Out << MostDerivedClass->getQualifiedNameAsString() << "', ";
// FIXME: Don't use / 8 .
Out << MostDerivedClassOffset / 8 << ") in '";
Out << LayoutClass->getQualifiedNameAsString();
+ } else {
+ Out << "Vtable for '";
+ Out << MostDerivedClass->getQualifiedNameAsString();
}
Out << "' (" << Components.size() << " entries).\n";
@@ -1945,8 +2027,6 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
AddressPointsByIndex.insert(std::make_pair(Index, Base));
}
- unsigned NextReturnAdjustmentIndex = 0;
- unsigned NextThisAdjustmentIndex = 0;
for (unsigned I = 0, E = Components.size(); I != E; ++I) {
uint64_t Index = I;
@@ -1983,38 +2063,33 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
if (MD->isPure())
Out << " [pure]";
- // If this function pointer has a return adjustment, dump it.
- if (NextReturnAdjustmentIndex < ReturnAdjustments.size() &&
- ReturnAdjustments[NextReturnAdjustmentIndex].first == I) {
- const ReturnAdjustment Adjustment =
- ReturnAdjustments[NextReturnAdjustmentIndex].second;
-
- Out << "\n [return adjustment: ";
- Out << Adjustment.NonVirtual << " non-virtual";
-
- if (Adjustment.VBaseOffsetOffset)
- Out << ", " << Adjustment.VBaseOffsetOffset << " vbase offset offset";
-
- Out << ']';
+ ThunkInfo Thunk = Thunks.lookup(I);
+ if (!Thunk.isEmpty()) {
+ // If this function pointer has a return adjustment, dump it.
+ if (!Thunk.Return.isEmpty()) {
+ Out << "\n [return adjustment: ";
+ Out << Thunk.Return.NonVirtual << " non-virtual";
+
+ if (Thunk.Return.VBaseOffsetOffset) {
+ Out << ", " << Thunk.Return.VBaseOffsetOffset;
+ Out << " vbase offset offset";
+ }
- NextReturnAdjustmentIndex++;
- }
-
- // If this function pointer has a 'this' pointer adjustment, dump it.
- if (NextThisAdjustmentIndex < ThisAdjustments.size() &&
- ThisAdjustments[NextThisAdjustmentIndex].first == I) {
- const ThisAdjustment Adjustment =
- ThisAdjustments[NextThisAdjustmentIndex].second;
-
- Out << "\n [this adjustment: ";
- Out << Adjustment.NonVirtual << " non-virtual";
+ Out << ']';
+ }
- if (Adjustment.VCallOffsetOffset)
- Out << ", " << Adjustment.VCallOffsetOffset << " vcall offset offset";
+ // If this function pointer has a 'this' pointer adjustment, dump it.
+ if (!Thunk.This.isEmpty()) {
+ Out << "\n [this adjustment: ";
+ Out << Thunk.This.NonVirtual << " non-virtual";
+
+ if (Thunk.This.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.VCallOffsetOffset;
+ Out << " vcall offset offset";
+ }
- Out << ']';
-
- NextThisAdjustmentIndex++;
+ Out << ']';
+ }
}
break;
@@ -2036,23 +2111,21 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
if (DD->isPure())
Out << " [pure]";
- // If this destructor has a 'this' pointer adjustment, dump it.
- if (NextThisAdjustmentIndex < ThisAdjustments.size() &&
- ThisAdjustments[NextThisAdjustmentIndex].first == I) {
- const ThisAdjustment Adjustment =
- ThisAdjustments[NextThisAdjustmentIndex].second;
-
- Out << "\n [this adjustment: ";
- Out << Adjustment.NonVirtual << " non-virtual";
-
- if (Adjustment.VCallOffsetOffset)
- Out << ", " << Adjustment.VCallOffsetOffset << " vcall offset offset";
-
- Out << ']';
-
- NextThisAdjustmentIndex++;
- }
-
+ ThunkInfo Thunk = Thunks.lookup(I);
+ if (!Thunk.isEmpty()) {
+ // If this destructor has a 'this' pointer adjustment, dump it.
+ if (!Thunk.This.isEmpty()) {
+ Out << "\n [this adjustment: ";
+ Out << Thunk.This.NonVirtual << " non-virtual";
+
+ if (Thunk.This.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.VCallOffsetOffset;
+ Out << " vcall offset offset";
+ }
+
+ Out << ']';
+ }
+ }
break;
}
@@ -2108,6 +2181,29 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
}
Out << '\n';
+
+ if (!isBuildingConstructorVtable() && MostDerivedClass->getNumVBases()) {
+ Out << "Virtual base offset offsets for '";
+ Out << MostDerivedClass->getQualifiedNameAsString() << "'.\n";
+
+ // 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;
+
+ 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));
+ }
+
+ for (std::map<std::string, int64_t>::const_iterator I =
+ ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end();
+ I != E; ++I)
+ Out << " " << I->first << " | " << I->second << '\n';
+
+ Out << "\n";
+ }
}
}
@@ -2598,7 +2694,7 @@ public:
CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
if (D != MostDerivedClass)
- return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
+ return CGM.getVtableInfo().getVirtualBaseOffsetOffset(D, B);
llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i;
i = VBIndex.find(B);
if (i != VBIndex.end())
@@ -3346,39 +3442,39 @@ CGVtableInfo::getAdjustments(GlobalDecl GD) {
return 0;
}
-int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase) {
+int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase) {
ClassPairTy ClassPair(RD, VBase);
- VirtualBaseClassIndiciesTy::iterator I =
- VirtualBaseClassIndicies.find(ClassPair);
- if (I != VirtualBaseClassIndicies.end())
+ VirtualBaseClassOffsetOffsetsMapTy::iterator I =
+ VirtualBaseClassOffsetOffsets.find(ClassPair);
+ if (I != VirtualBaseClassOffsetOffsets.end())
return I->second;
- // FIXME: This seems expensive. Can we do a partial job to get
- // just this data.
- AddressPointsMapTy AddressPoints;
- OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
- D1(printf("vtable %s\n", RD->getNameAsCString()));
- b.GenerateVtableForBase(RD);
- b.GenerateVtableForVBases(RD);
+ VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0,
+ BaseSubobject(RD, 0),
+ /*BaseIsVirtual=*/false,
+ /*OffsetInLayoutClass=*/0);
- for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
- b.getVBIndex().begin(), E = b.getVBIndex().end(); I != E; ++I) {
+
+ for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
+ Builder.getVBaseOffsetOffsets().begin(),
+ E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
// Insert all types.
ClassPairTy ClassPair(RD, I->first);
- VirtualBaseClassIndicies.insert(std::make_pair(ClassPair, I->second));
+ VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second));
}
- I = VirtualBaseClassIndicies.find(ClassPair);
+ I = VirtualBaseClassOffsetOffsets.find(ClassPair);
+
// FIXME: The assertion below assertion currently fails with the old vtable
/// layout code if there is a non-virtual thunk adjustment in a vtable.
// Once the new layout is in place, this return should be removed.
- if (I == VirtualBaseClassIndicies.end())
+ if (I == VirtualBaseClassOffsetOffsets.end())
return 0;
- assert(I != VirtualBaseClassIndicies.end() && "Did not find index!");
+ assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!");
return I->second;
}
@@ -3400,20 +3496,17 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
if (GenerateDefinition) {
if (LayoutClass == RD) {
assert(!IsVirtual &&
- "Can't only have a virtual base in construction vtables!");
- VtableBuilder Builder(*this, RD, Offset,
- /*MostDerivedClassIsVirtual=*/false,
- LayoutClass);
-
- if (CGM.getLangOptions().DumpVtableLayouts)
- Builder.dumpLayout(llvm::errs());
- } else if (CGM.getLangOptions().DumpVtableLayouts) {
- // We only build construction vtables when dumping vtable layouts for now.
- VtableBuilder Builder(*this, RD, Offset,
- /*MostDerivedClassIsVirtual=*/IsVirtual,
- LayoutClass);
- Builder.dumpLayout(llvm::errs());
+ "Can only have a virtual base in construction vtables!");
+ assert(!Offset &&
+ "Can only have a base offset in construction vtables!");
}
+
+ VtableBuilder Builder(*this, RD, Offset,
+ /*MostDerivedClassIsVirtual=*/IsVirtual,
+ LayoutClass);
+
+ if (CGM.getLangOptions().DumpVtableLayouts)
+ Builder.dumpLayout(llvm::errs());
}
llvm::SmallString<256> OutName;
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 57220d9d5af5..5a146ab97c99 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -149,10 +149,12 @@ private:
typedef std::pair<const CXXRecordDecl *,
const CXXRecordDecl *> ClassPairTy;
- /// VirtualBaseClassIndicies - Contains the index into the vtable where the
- /// offsets for virtual bases of a class are stored.
- typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy;
- VirtualBaseClassIndiciesTy VirtualBaseClassIndicies;
+ /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
+ /// the address point) in bytes where the offsets for virtual bases of a class
+ /// are stored.
+ typedef llvm::DenseMap<ClassPairTy, int64_t>
+ VirtualBaseClassOffsetOffsetsMapTy;
+ VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
/// Vtables - All the vtables which have been defined.
llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> Vtables;
@@ -202,13 +204,13 @@ public:
/// stored.
uint64_t getMethodVtableIndex(GlobalDecl GD);
- /// getVirtualBaseOffsetIndex - Return the index (relative to the vtable
- /// address point) where the offset of the virtual base that contains the
- /// given Base is stored, otherwise, if no virtual base contains the given
+ /// getVirtualBaseOffsetOffset - Return the offset in bytes (relative to the
+ /// vtable address point) where the offset of the virtual base that contains
+ /// the given base is stored, otherwise, if no virtual base contains the given
/// class, return 0. Base must be a virtual base class or an unambigious
/// base.
- int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase);
+ int64_t getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase);
AdjustmentVectorTy *getAdjustments(GlobalDecl GD);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index c67948d27f08..f41db14f1a66 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -285,8 +285,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
break;
case TSK_ExplicitInstantiationDefinition:
- // FIXME: explicit instantiation definitions should use weak linkage
- return CodeGenModule::GVA_StrongExternal;
+ return CodeGenModule::GVA_ExplicitTemplateInstantiation;
case TSK_ExplicitInstantiationDeclaration:
case TSK_ImplicitInstantiation:
@@ -343,6 +342,12 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
// merged with other definitions. c) C++ has the ODR, so we know the
// definition is dependable.
return llvm::Function::LinkOnceODRLinkage;
+ } else if (Linkage == GVA_ExplicitTemplateInstantiation) {
+ // An explicit instantiation of a template has weak linkage, since
+ // explicit instantiations can occur in multiple translation units
+ // and must all be equivalent. However, we are not allowed to
+ // throw away these explicit instantiations.
+ return llvm::Function::WeakODRLinkage;
} else {
assert(Linkage == GVA_StrongExternal);
// Otherwise, we have strong external linkage.
@@ -589,6 +594,7 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// static, static inline, always_inline, and extern inline functions can
// always be deferred. Normal inline functions can be deferred in C99/C++.
+ // Implicit template instantiations can also be deferred in C++.
if (Linkage == GVA_Internal || Linkage == GVA_C99Inline ||
Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
return true;
@@ -1043,15 +1049,15 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
switch (TSK) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
-
- // FIXME: ExplicitInstantiationDefinition should be weak!
- case TSK_ExplicitInstantiationDefinition:
return CodeGenModule::GVA_StrongExternal;
-
+
case TSK_ExplicitInstantiationDeclaration:
llvm_unreachable("Variable should not be instantiated");
// Fall through to treat this like any other instantiation.
+ case TSK_ExplicitInstantiationDefinition:
+ return CodeGenModule::GVA_ExplicitTemplateInstantiation;
+
case TSK_ImplicitInstantiation:
return CodeGenModule::GVA_TemplateInstantiation;
}
@@ -1171,7 +1177,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setLinkage(llvm::GlobalVariable::WeakODRLinkage);
else
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
- } else if (Linkage == GVA_TemplateInstantiation)
+ } else if (Linkage == GVA_TemplateInstantiation ||
+ Linkage == GVA_ExplicitTemplateInstantiation)
+ // FIXME: It seems like we can provide more specific linkage here
+ // (LinkOnceODR, WeakODR).
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
else if (!getLangOptions().CPlusPlus && !CodeGenOpts.NoCommon &&
!D->hasExternalStorage() && !D->getInit() &&
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 40dc56388981..9077adedd0b9 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -437,7 +437,8 @@ public:
GVA_C99Inline,
GVA_CXXInline,
GVA_StrongExternal,
- GVA_TemplateInstantiation
+ GVA_TemplateInstantiation,
+ GVA_ExplicitTemplateInstantiation
};
llvm::GlobalVariable::LinkageTypes
diff --git a/lib/CodeGen/Makefile b/lib/CodeGen/Makefile
index 83cb36738709..3cea6bbd9f06 100644
--- a/lib/CodeGen/Makefile
+++ b/lib/CodeGen/Makefile
@@ -16,9 +16,9 @@ LEVEL = ../../../..
LIBRARYNAME := clangCodeGen
BUILD_ARCHIVE = 1
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
ifdef CLANG_VENDOR
-CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "'
+CPP.Flags += -DCLANG_VENDOR='"$(CLANG_VENDOR) "'
endif
include $(LEVEL)/Makefile.common
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 2e0580f5e79b..32555ab70579 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -53,19 +53,19 @@ static const DeclContext *GetLocalClassFunctionDeclContext(
static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
"Passed in decl is not a ctor or dtor!");
-
+
if (const TemplateDecl *TD = MD->getPrimaryTemplate()) {
MD = cast<CXXMethodDecl>(TD->getTemplatedDecl());
assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
"Templated decl is not a ctor or dtor!");
}
-
+
return MD;
}
static const unsigned UnknownArity = ~0U;
-
+
/// CXXNameMangler - Manage the mangling of a single name.
class CXXNameMangler {
MangleContext &Context;
@@ -73,7 +73,7 @@ class CXXNameMangler {
const CXXMethodDecl *Structor;
unsigned StructorType;
-
+
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
ASTContext &getASTContext() const { return Context.getASTContext(); }
@@ -92,7 +92,7 @@ public:
~CXXNameMangler() {
if (Out.str()[0] == '\01')
return;
-
+
int status = 0;
char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status);
assert(status == 0 && "Could not demangle mangled name!");
@@ -151,7 +151,7 @@ private:
void mangleQualifiers(Qualifiers Quals);
void mangleObjCMethodName(const ObjCMethodDecl *MD);
-
+
// Declare manglers for every type class.
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT)
@@ -172,10 +172,12 @@ private:
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
- void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+ void mangleTemplateArgs(const TemplateParameterList &PL,
+ const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleTemplateArgs(const TemplateArgumentList &L);
- void mangleTemplateArg(const TemplateArgument &A);
+ void mangleTemplateArgs(const TemplateParameterList &PL,
+ const TemplateArgumentList &AL);
+ void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A);
void mangleTemplateParameter(unsigned Index);
};
@@ -248,8 +250,10 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
Out << Prefix;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
mangleFunctionEncoding(FD);
+ else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ mangleName(VD);
else
- mangleName(cast<VarDecl>(D));
+ mangleName(cast<FieldDecl>(D));
}
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
@@ -306,7 +310,7 @@ static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
DC = DC->getParent();
}
-
+
return DC;
}
@@ -315,10 +319,10 @@ static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
static bool isStdNamespace(const DeclContext *DC) {
if (!DC->isNamespace())
return false;
-
+
if (!IgnoreLinkageSpecDecls(DC->getParent())->isTranslationUnit())
return false;
-
+
return isStd(cast<NamespaceDecl>(DC));
}
@@ -349,12 +353,12 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
// ::= <local-name>
//
const DeclContext *DC = ND->getDeclContext();
-
+
if (GetLocalClassFunctionDeclContext(DC)) {
mangleLocalName(ND);
return;
}
-
+
// If this is an extern variable declared locally, the relevant DeclContext
// is that of the containing namespace, or the translation unit.
if (isa<FunctionDecl>(DC) && ND->hasLinkage())
@@ -369,7 +373,8 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleUnscopedTemplateName(TD);
- mangleTemplateArgs(*TemplateArgs);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
return;
}
@@ -391,7 +396,8 @@ void CXXNameMangler::mangleName(const TemplateDecl *TD,
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD);
- mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs);
} else {
mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
}
@@ -417,7 +423,7 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
= dyn_cast<TemplateTemplateParmDecl>(ND)) {
mangleTemplateParameter(TTP->getIndex());
return;
- }
+ }
mangleUnscopedName(ND->getTemplatedDecl());
addSubstitution(ND);
@@ -429,7 +435,7 @@ void CXXNameMangler::mangleNumber(int64_t Number) {
Out << 'n';
Number = -Number;
}
-
+
Out << Number;
}
@@ -445,7 +451,7 @@ void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) {
Out << '_';
return;
}
-
+
Out << 'v';
mangleNumber(Adjustment.NonVirtual);
Out << '_';
@@ -496,7 +502,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
case DeclarationName::Identifier: {
if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
// We must avoid conflicts between internally- and externally-
- // linked variable declaration names in the same TU.
+ // linked variable declaration names in the same TU.
// This naming convention is the same as that followed by GCC, though it
// shouldn't actually matter.
if (ND && isa<VarDecl>(ND) && ND->getLinkage() == InternalLinkage &&
@@ -582,7 +588,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
unsigned Arity;
if (ND) {
Arity = cast<FunctionDecl>(ND)->getNumParams();
-
+
// If we have a C++ member function, we need to include the 'this' pointer.
// FIXME: This does not make sense for operators that are static, but their
// names stay the same regardless of the arity (operator new for instance).
@@ -628,7 +634,8 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
- mangleTemplateArgs(*TemplateArgs);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
}
else {
manglePrefix(DC, NoFunction);
@@ -645,7 +652,8 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
Out << 'N';
mangleTemplatePrefix(TD);
- mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs);
Out << 'E';
}
@@ -656,26 +664,26 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
// <discriminator> := _ <non-negative number>
const DeclContext *DC = ND->getDeclContext();
Out << 'Z';
-
+
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC))
mangleObjCMethodName(MD);
else if (const DeclContext *CDC = GetLocalClassFunctionDeclContext(DC)) {
mangleFunctionEncoding(cast<FunctionDecl>(CDC));
Out << 'E';
mangleNestedName(ND, DC, true /*NoFunction*/);
-
+
// FIXME. This still does not cover all cases.
unsigned disc;
if (Context.getNextDiscriminator(ND, disc)) {
if (disc < 10)
Out << '_' << disc;
- else
+ else
Out << "__" << disc << '_';
}
return;
}
- else
+ else
mangleFunctionEncoding(cast<FunctionDecl>(DC));
Out << 'E';
@@ -702,7 +710,8 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
mangleTemplatePrefix(TD);
- mangleTemplateArgs(*TemplateArgs);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
}
else if(NoFunction && isa<FunctionDecl>(DC))
return;
@@ -729,7 +738,7 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
= dyn_cast<TemplateTemplateParmDecl>(ND)) {
mangleTemplateParameter(TTP->getIndex());
return;
- }
+ }
manglePrefix(ND->getDeclContext());
mangleUnqualifiedName(ND->getTemplatedDecl());
@@ -749,22 +758,22 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
case OO_Array_Delete: Out << "da"; break;
// ::= ps # + (unary)
// ::= pl # +
- case OO_Plus:
+ case OO_Plus:
assert((Arity == 1 || Arity == 2) && "Invalid arity!");
Out << (Arity == 1? "ps" : "pl"); break;
// ::= ng # - (unary)
// ::= mi # -
- case OO_Minus:
+ case OO_Minus:
assert((Arity == 1 || Arity == 2) && "Invalid arity!");
Out << (Arity == 1? "ng" : "mi"); break;
// ::= ad # & (unary)
// ::= an # &
- case OO_Amp:
+ case OO_Amp:
assert((Arity == 1 || Arity == 2) && "Invalid arity!");
Out << (Arity == 1? "ad" : "an"); break;
// ::= de # * (unary)
// ::= ml # *
- case OO_Star:
+ case OO_Star:
assert((Arity == 1 || Arity == 2) && "Invalid arity!");
Out << (Arity == 1? "de" : "ml"); break;
// ::= co # ~
@@ -863,15 +872,15 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
llvm::SmallString<64> Name;
llvm::raw_svector_ostream OS(Name);
-
- const ObjCContainerDecl *CD =
+
+ const ObjCContainerDecl *CD =
dyn_cast<ObjCContainerDecl>(MD->getDeclContext());
assert (CD && "Missing container decl in GetNameForMethod");
OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
OS << '(' << CID->getNameAsString() << ')';
OS << ' ' << MD->getSelector().getAsString() << ']';
-
+
Out << OS.str().size() << OS.str();
}
@@ -1143,7 +1152,9 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
assert(TD && "FIXME: Support dependent template names");
mangleTemplatePrefix(TD);
- mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, TST->getArgs(),
+ TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
} else if (const TemplateTypeParmType *TTPT =
@@ -1173,7 +1184,7 @@ void CXXNameMangler::mangleType(const TypeOfExprType *T) {
void CXXNameMangler::mangleType(const DecltypeType *T) {
Expr *E = T->getUnderlyingExpr();
-
+
// type ::= Dt <expression> E # decltype of an id-expression
// # or class member access
// ::= DT <expression> E # decltype of an expression
@@ -1195,11 +1206,11 @@ void CXXNameMangler::mangleType(const DecltypeType *T) {
Out << 'E';
}
-void CXXNameMangler::mangleIntegerLiteral(QualType T,
+void CXXNameMangler::mangleIntegerLiteral(QualType T,
const llvm::APSInt &Value) {
// <expr-primary> ::= L <type> <value number> E # integer literal
Out << 'L';
-
+
mangleType(T);
if (T->isBooleanType()) {
// Boolean values are encoded as 0/1.
@@ -1210,7 +1221,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T,
Value.abs().print(Out, false);
}
Out << 'E';
-
+
}
void CXXNameMangler::mangleCalledExpression(const Expr *E, unsigned Arity) {
@@ -1314,7 +1325,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
break;
}
- case Expr::CXXUnresolvedConstructExprClass: {
+ case Expr::CXXUnresolvedConstructExprClass: {
const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E);
unsigned N = CE->arg_size();
@@ -1323,7 +1334,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
if (N != 1) Out << "_";
for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
if (N != 1) Out << "E";
- break;
+ break;
}
case Expr::CXXTemporaryObjectExprClass:
@@ -1355,18 +1366,18 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
case Expr::UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(E);
- mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()),
+ mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()),
/*Arity=*/1);
mangleExpression(UO->getSubExpr());
break;
}
-
+
case Expr::BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(E);
- mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
+ mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
/*Arity=*/2);
mangleExpression(BO->getLHS());
- mangleExpression(BO->getRHS());
+ mangleExpression(BO->getRHS());
break;
}
@@ -1396,7 +1407,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
mangleExpression(ECE->getSubExpr());
break;
}
-
+
case Expr::CXXOperatorCallExprClass: {
const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
unsigned NumArgs = CE->getNumArgs();
@@ -1406,7 +1417,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
mangleExpression(CE->getArg(i));
break;
}
-
+
case Expr::ParenExprClass:
mangleExpression(cast<ParenExpr>(E)->getSubExpr());
break;
@@ -1415,7 +1426,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
switch (D->getKind()) {
- default:
+ default:
// <expr-primary> ::= L <mangled-name> E # external name
Out << 'L';
mangle(D, "_Z");
@@ -1466,7 +1477,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
mangleType(FL->getType());
// TODO: avoid this copy with careful stream management.
- llvm::SmallVector<char,20> Buffer;
+ llvm::SmallString<20> Buffer;
FL->getValue().bitcastToAPInt().toString(Buffer, 16, false);
Out.write(Buffer.data(), Buffer.size());
@@ -1475,7 +1486,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
}
case Expr::IntegerLiteralClass:
- mangleIntegerLiteral(E->getType(),
+ mangleIntegerLiteral(E->getType(),
llvm::APSInt(cast<IntegerLiteral>(E)->getValue()));
break;
@@ -1521,24 +1532,27 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
}
}
-void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &L) {
+void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
+ const TemplateArgumentList &AL) {
// <template-args> ::= I <template-arg>+ E
Out << "I";
- for (unsigned i = 0, e = L.size(); i != e; ++i)
- mangleTemplateArg(L[i]);
+ for (unsigned i = 0, e = AL.size(); i != e; ++i)
+ mangleTemplateArg(PL.getParam(i), AL[i]);
Out << "E";
}
-void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
+ const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << "I";
for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(TemplateArgs[i]);
+ mangleTemplateArg(PL.getParam(i), TemplateArgs[i]);
Out << "E";
}
-void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) {
+void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
+ const TemplateArgument &A) {
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
@@ -1554,7 +1568,7 @@ void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) {
assert(A.getAsTemplate().getAsTemplateDecl() &&
"FIXME: Support dependent template names");
mangleName(A.getAsTemplate().getAsTemplateDecl());
- break;
+ break;
case TemplateArgument::Expression:
Out << 'X';
mangleExpression(A.getAsExpr());
@@ -1566,18 +1580,33 @@ void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) {
case TemplateArgument::Declaration: {
// <expr-primary> ::= L <mangled-name> E # external name
- // FIXME: Clang produces AST's where pointer-to-member-function expressions
+ // Clang produces AST's where pointer-to-member-function expressions
// and pointer-to-function expressions are represented as a declaration not
- // an expression; this is not how gcc represents them and this changes the
- // mangling.
+ // an expression. We compensate for it here to produce the correct mangling.
+ NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
+ const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P);
+ bool compensateMangling = D->isCXXClassMember() &&
+ !Parameter->getType()->isReferenceType();
+ if (compensateMangling) {
+ Out << 'X';
+ mangleOperatorName(OO_Amp, 1);
+ }
+
Out << 'L';
// References to external entities use the mangled name; if the name would
// not normally be manged then mangle it as unqualified.
//
// FIXME: The ABI specifies that external names here should have _Z, but
// gcc leaves this off.
- mangle(cast<NamedDecl>(A.getAsDecl()), "Z");
+ if (compensateMangling)
+ mangle(D, "_Z");
+ else
+ mangle(D, "Z");
Out << 'E';
+
+ if (compensateMangling)
+ Out << 'E';
+
break;
}
}
@@ -1689,20 +1718,20 @@ bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl *SD,
const char (&Str)[StrLen]) {
if (!SD->getIdentifier()->isStr(Str))
return false;
-
+
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
if (TemplateArgs.size() != 2)
return false;
-
+
if (!isCharType(TemplateArgs[0].getAsType()))
return false;
-
+
if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
return false;
-
+
return true;
}
-
+
bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
// <substitution> ::= St # ::std::
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
@@ -1769,7 +1798,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
Out << "So";
return true;
}
-
+
// <substitution> ::= Sd # ::std::basic_iostream<char,
// ::std::char_traits<char> >
if (isStreamCharSpecialization(SD, "basic_iostream")) {
@@ -1838,7 +1867,7 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
/// \brief Mangles the a thunk with the offset n for the declaration D and
/// emits that name to the given output stream.
-void MangleContext::mangleThunk(const FunctionDecl *FD,
+void MangleContext::mangleThunk(const FunctionDecl *FD,
const ThunkAdjustment &ThisAdjustment,
llvm::SmallVectorImpl<char> &Res) {
assert(!isa<CXXDestructorDecl>(FD) &&
@@ -1866,7 +1895,7 @@ void MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *D,
/// \brief Mangles the a covariant thunk for the declaration D and emits that
/// name to the given output stream.
-void
+void
MangleContext::mangleCovariantThunk(const FunctionDecl *FD,
const CovariantThunkAdjustment& Adjustment,
llvm::SmallVectorImpl<char> &Res) {
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index cb6a7df68d45..59e8e77756cd 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -268,16 +268,15 @@ llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
ASTContext &Context,
llvm::LLVMContext &VMContext) const {
- if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ if (CodeGenFunction::hasAggregateLLVMType(Ty))
return ABIArgInfo::getIndirect(0);
- } else {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- }
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
/// X86_32ABIInfo - The X86-32 ABI information.
@@ -1367,6 +1366,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// i8* reg_save_area;
// };
unsigned neededInt, neededSSE;
+
+ Ty = CGF.getContext().getCanonicalType(Ty);
ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext,
neededInt, neededSSE);
@@ -1596,6 +1597,80 @@ llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
}
+// PowerPC-32
+
+namespace {
+class PPC32TargetCodeGenInfo : public DefaultTargetCodeGenInfo {
+public:
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ // This is recovered from gcc output.
+ return 1; // r1 is the dedicated stack pointer
+ }
+
+ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const;
+};
+
+}
+
+bool
+PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ // This is calculated from the LLVM and GCC tables and verified
+ // against gcc output. AFAIK all ABIs use the same encoding.
+
+ CodeGen::CGBuilderTy &Builder = CGF.Builder;
+ llvm::LLVMContext &Context = CGF.getLLVMContext();
+
+ const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
+ llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
+ llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16);
+
+ // 0-31: r0-31, the 4-byte general-purpose registers
+ for (unsigned I = 0, E = 32; I != E; ++I) {
+ llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
+ Builder.CreateStore(Four8, Slot);
+ }
+
+ // 32-63: fp0-31, the 8-byte floating-point registers
+ for (unsigned I = 32, E = 64; I != E; ++I) {
+ llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
+ Builder.CreateStore(Eight8, Slot);
+ }
+
+ // 64-76 are various 4-byte special-purpose registers:
+ // 64: mq
+ // 65: lr
+ // 66: ctr
+ // 67: ap
+ // 68-75 cr0-7
+ // 76: xer
+ for (unsigned I = 64, E = 77; I != E; ++I) {
+ llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
+ Builder.CreateStore(Four8, Slot);
+ }
+
+ // 77-108: v0-31, the 16-byte vector registers
+ for (unsigned I = 77, E = 109; I != E; ++I) {
+ llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
+ Builder.CreateStore(Sixteen8, Slot);
+ }
+
+ // 109: vrsave
+ // 110: vscr
+ // 111: spe_acc
+ // 112: spefscr
+ // 113: sfp
+ for (unsigned I = 109, E = 114; I != E; ++I) {
+ llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
+ Builder.CreateStore(Four8, Slot);
+ }
+
+ return false;
+}
+
+
// ARM ABI Implementation
namespace {
@@ -2040,6 +2115,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const {
case llvm::Triple::pic16:
return *(TheTargetCodeGenInfo = new PIC16TargetCodeGenInfo());
+ case llvm::Triple::ppc:
+ return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo());
+
case llvm::Triple::systemz:
return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo());
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index 62434893f939..b9a3306d53c9 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -13,8 +13,10 @@
using namespace clang::driver;
Action::~Action() {
- // FIXME: Free the inputs. The problem is that BindArchAction shares
- // inputs; so we can't just walk the inputs.
+ if (OwnsInputs) {
+ for (iterator it = begin(), ie = end(); it != ie; ++it)
+ delete *it;
+ }
}
const char *Action::getClassName(ActionClass AC) {
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index 8a57d14932d3..95805b016b1f 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -80,9 +80,9 @@ Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
Arg *A1 = getLastArgNoClaim(Id1);
Arg *A2 = getLastArgNoClaim(Id2);
- int A0Idx = A0 ? A0->getIndex() : -1;
- int A1Idx = A1 ? A1->getIndex() : -1;
- int A2Idx = A2 ? A2->getIndex() : -1;
+ int A0Idx = A0 ? (int) A0->getIndex() : -1;
+ int A1Idx = A1 ? (int) A1->getIndex() : -1;
+ int A2Idx = A2 ? (int) A2->getIndex() : -1;
if (A0Idx > A1Idx) {
if (A0Idx > A2Idx)
@@ -218,23 +218,30 @@ const char *DerivedArgList::MakeArgString(llvm::StringRef Str) const {
}
Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option *Opt) const {
- return new FlagArg(Opt, BaseArgs.MakeIndex(Opt->getName()), BaseArg);
+ Arg *A = new FlagArg(Opt, BaseArgs.MakeIndex(Opt->getName()), BaseArg);
+ SynthesizedArgs.push_back(A);
+ return A;
}
Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt,
llvm::StringRef Value) const {
- return new PositionalArg(Opt, BaseArgs.MakeIndex(Value), BaseArg);
+ Arg *A = new PositionalArg(Opt, BaseArgs.MakeIndex(Value), BaseArg);
+ SynthesizedArgs.push_back(A);
+ return A;
}
Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
llvm::StringRef Value) const {
- return new SeparateArg(Opt, BaseArgs.MakeIndex(Opt->getName(), Value), 1,
- BaseArg);
+ Arg *A = new SeparateArg(Opt, BaseArgs.MakeIndex(Opt->getName(), Value), 1,
+ BaseArg);
+ SynthesizedArgs.push_back(A);
+ return A;
}
Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
llvm::StringRef Value) const {
- std::string Joined(Opt->getName());
- Joined += Value;
- return new JoinedArg(Opt, BaseArgs.MakeIndex(Joined.c_str()), BaseArg);
+ Arg *A = new JoinedArg(Opt, BaseArgs.MakeIndex(Opt->getName() + Value.str()),
+ BaseArg);
+ SynthesizedArgs.push_back(A);
+ return A;
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 64168b4d8395..3257ee55a7b9 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -503,8 +503,11 @@ void Driver::BuildUniversalActions(const ArgList &Args,
<< types::getTypeName(Act->getType());
ActionList Inputs;
- for (unsigned i = 0, e = Archs.size(); i != e; ++i)
+ for (unsigned i = 0, e = Archs.size(); i != e; ++i) {
Inputs.push_back(new BindArchAction(Act, Archs[i]));
+ if (i != 0)
+ Inputs.back()->setOwnsInputs(false);
+ }
// Lipo if necessary, we do it this way because we need to set the arch flag
// so that -Xarch_ gets overwritten.
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 1bd123e220ec..bfeb41a94299 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -23,8 +23,18 @@ Command::Command(const Action &_Source, const Tool &_Creator,
PipedJob::PipedJob() : Job(PipedJobClass) {}
+PipedJob::~PipedJob() {
+ for (iterator it = begin(), ie = end(); it != ie; ++it)
+ delete *it;
+}
+
JobList::JobList() : Job(JobListClass) {}
+JobList::~JobList() {
+ for (iterator it = begin(), ie = end(); it != ie; ++it)
+ delete *it;
+}
+
void Job::addCommand(Command *C) {
if (PipedJob *PJ = dyn_cast<PipedJob>(this))
PJ->addCommand(C);
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 63cf98d3da5d..3bf1fab1c27d 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -35,8 +35,9 @@
#include "llvm/System/Path.h"
using namespace clang;
-ASTUnit::ASTUnit(bool _MainFileIsAST)
- : MainFileIsAST(_MainFileIsAST), ConcurrencyCheckValue(CheckUnlocked) {
+ASTUnit::ASTUnit(Diagnostic &Diag, bool _MainFileIsAST)
+ : SourceMgr(Diag), MainFileIsAST(_MainFileIsAST),
+ ConcurrencyCheckValue(CheckUnlocked) {
}
ASTUnit::~ASTUnit() {
ConcurrencyCheckValue = CheckLocked;
@@ -146,7 +147,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles,
bool CaptureDiagnostics) {
- llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
+ llvm::OwningPtr<ASTUnit> AST(new ASTUnit(Diags, true));
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
@@ -311,7 +312,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
"FIXME: AST inputs not yet supported here!");
// Create the AST unit.
- AST.reset(new ASTUnit(false));
+ AST.reset(new ASTUnit(Diags, false));
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index c845d56f4ec1..02d6cec8fcab 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -196,6 +196,11 @@ class PTHWriter {
Out.write(Ptr, NumBytes);
}
+ void EmitString(llvm::StringRef V) {
+ ::Emit16(Out, V.size());
+ EmitBuf(V.data(), V.size());
+ }
+
/// EmitIdentifierTable - Emits two tables to the PTH file. The first is
/// a hashtable mapping from identifier strings to persistent IDs.
/// The second is a straight table mapping from persistent IDs to string data
@@ -214,7 +219,7 @@ public:
: Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
PTHMap &getPM() { return PM; }
- void GeneratePTH(const std::string *MainFile = 0);
+ void GeneratePTH(const std::string &MainFile);
};
} // end anonymous namespace
@@ -295,7 +300,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
}
if (Tok.is(tok::identifier)) {
- Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
+ PP.LookUpIdentifierInfo(Tok);
EmitToken(Tok);
continue;
}
@@ -321,7 +326,6 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
}
IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok);
- Tok.setIdentifierInfo(II);
tok::PPKeywordKind K = II->getPPKeywordID();
ParsingPreprocessorDirective = true;
@@ -344,7 +348,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
L.setParsingPreprocessorDirective(false);
assert(!Tok.isAtStartOfLine());
if (Tok.is(tok::identifier))
- Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
+ PP.LookUpIdentifierInfo(Tok);
break;
}
@@ -436,7 +440,7 @@ Offset PTHWriter::EmitCachedSpellings() {
return SpellingsOff;
}
-void PTHWriter::GeneratePTH(const std::string *MainFile) {
+void PTHWriter::GeneratePTH(const std::string &MainFile) {
// Generate the prologue.
Out << "cfe-pth";
Emit32(PTHManager::Version);
@@ -447,9 +451,8 @@ void PTHWriter::GeneratePTH(const std::string *MainFile) {
Emit32(0);
// Write the name of the MainFile.
- if (MainFile && !MainFile->empty()) {
- Emit16(MainFile->length());
- EmitBuf(MainFile->data(), MainFile->length());
+ if (!MainFile.empty()) {
+ EmitString(MainFile);
} else {
// String with 0 bytes.
Emit16(0);
@@ -471,7 +474,7 @@ void PTHWriter::GeneratePTH(const std::string *MainFile) {
if (!P.isAbsolute())
continue;
- const llvm::MemoryBuffer *B = C.getBuffer();
+ const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics());
if (!B) continue;
FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
@@ -533,15 +536,8 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
const SourceManager &SrcMgr = PP.getSourceManager();
const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID());
llvm::sys::Path MainFilePath(MainFile->getName());
- std::string MainFileName;
- if (!MainFilePath.isAbsolute()) {
- llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
- P.appendComponent(MainFilePath.str());
- MainFileName = P.str();
- } else {
- MainFileName = MainFilePath.str();
- }
+ MainFilePath.makeAbsolute();
// Create the PTHWriter.
PTHWriter PW(*OS, PP);
@@ -558,18 +554,18 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
// Generate the PTH file.
PP.getFileManager().removeStatCache(StatCache);
- PW.GeneratePTH(&MainFileName);
+ PW.GeneratePTH(MainFilePath.str());
}
//===----------------------------------------------------------------------===//
+namespace {
class PTHIdKey {
public:
const IdentifierInfo* II;
uint32_t FileOffset;
};
-namespace {
class PTHIdentifierTableTrait {
public:
typedef PTHIdKey* key_type;
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 25b804aba7fc..3bc566192965 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -185,7 +185,7 @@ void CompilerInstance::createFileManager() {
// Source Manager
void CompilerInstance::createSourceManager() {
- SourceMgr.reset(new SourceManager());
+ SourceMgr.reset(new SourceManager(getDiagnostics()));
}
// Preprocessor
@@ -294,6 +294,8 @@ void CompilerInstance::createCodeCompletionConsumer() {
getFrontendOpts().DebugCodeCompletionPrinter,
getFrontendOpts().ShowMacrosInCodeCompletion,
llvm::outs()));
+ if (!CompletionConsumer)
+ return;
if (CompletionConsumer->isOutputBinary() &&
llvm::sys::Program::ChangeStdoutToBinary()) {
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 64a42bc0ec40..5798f2f71005 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -474,6 +474,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fcatch-undefined-behavior");
if (Opts.WritableStrings)
Res.push_back("-fwritable-strings");
+ if (Opts.ConstStrings)
+ Res.push_back("-Wwrite-strings");
if (!Opts.LaxVectorConversions)
Res.push_back("-fno-lax-vector-conversions");
if (Opts.AltiVec)
@@ -1162,6 +1164,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
+ Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings);
if (Args.hasArg(OPT_fno_lax_vector_conversions))
Opts.LaxVectorConversions = 0;
if (Args.hasArg(OPT_fno_threadsafe_statics))
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
index f695254cb466..da99cb8b7b89 100644
--- a/lib/Frontend/HTMLDiagnostics.cpp
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -40,13 +40,13 @@ class HTMLDiagnostics : public PathDiagnosticClient {
std::vector<const PathDiagnostic*> BatchedDiags;
public:
HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp);
-
+
virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); }
-
+
virtual void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade);
virtual void HandlePathDiagnostic(const PathDiagnostic* D);
-
+
virtual llvm::StringRef getName() const {
return "HTMLDiagnostics";
}
@@ -108,7 +108,7 @@ HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade)
ReportDiag(*D, FilesMade);
delete D;
}
-
+
BatchedDiags.clear();
}
@@ -294,7 +294,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
llvm::raw_fd_ostream os(H.c_str(), ErrorMsg);
if (!ErrorMsg.empty()) {
- (llvm::errs() << "warning: could not create file '" << F.str()
+ (llvm::errs() << "warning: could not create file '" << F.str()
<< "'\n").flush();
return;
}
@@ -439,10 +439,10 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
{
FullSourceLoc L = MP->getLocation().asLocation().getInstantiationLoc();
assert(L.isFileID());
- std::pair<const char*, const char*> BufferInfo = L.getBufferData();
- const char* MacroName = L.getDecomposedLoc().second + BufferInfo.first;
- Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.first,
- MacroName, BufferInfo.second);
+ llvm::StringRef BufferInfo = L.getBufferData();
+ const char* MacroName = L.getDecomposedLoc().second + BufferInfo.data();
+ Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.begin(),
+ MacroName, BufferInfo.end());
Token TheTok;
rawLexer.LexFromRawLexer(TheTok);
@@ -502,19 +502,13 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
}
static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
- llvm::SmallVector<char, 10> buf;
-
- do {
- unsigned x = n % ('z' - 'a');
- buf.push_back('a' + x);
- n = n / ('z' - 'a');
- } while (n);
+ unsigned x = n % ('z' - 'a');
+ n /= 'z' - 'a';
- assert(!buf.empty());
+ if (n > 0)
+ EmitAlphaCounter(os, n);
- for (llvm::SmallVectorImpl<char>::reverse_iterator I=buf.rbegin(),
- E=buf.rend(); I!=E; ++I)
- os << *I;
+ os << char('a' + x);
}
unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os,
diff --git a/lib/Frontend/Makefile b/lib/Frontend/Makefile
index a630b0133632..9e1a864d96e3 100644
--- a/lib/Frontend/Makefile
+++ b/lib/Frontend/Makefile
@@ -11,7 +11,7 @@ LEVEL = ../../../..
LIBRARYNAME := clangFrontend
BUILD_ARCHIVE = 1
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 267f4c158508..49eb2a0e600d 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -2628,7 +2628,7 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) {
unsigned StrLen = (((unsigned) StrLenPtr[0])
| (((unsigned) StrLenPtr[1]) << 8)) - 1;
IdentifiersLoaded[ID - 1]
- = &PP->getIdentifierTable().get(Str, Str + StrLen);
+ = &PP->getIdentifierTable().get(Str, StrLen);
}
return IdentifiersLoaded[ID - 1];
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index a3f5eac480cd..f847becb15b8 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -131,10 +131,11 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
TD->setDefinition(Record[Idx++]);
TD->setEmbeddedInDeclarator(Record[Idx++]);
- TD->setTypedefForAnonDecl(
- cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
TD->setTagKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ // FIXME: maybe read optional qualifier and its range.
+ TD->setTypedefForAnonDecl(
+ cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
}
void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) {
@@ -168,6 +169,7 @@ void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx);
if (TInfo)
DD->setTypeSourceInfo(TInfo);
+ // FIXME: read optional qualifier and its range.
}
void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
@@ -411,6 +413,7 @@ void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
VisitVarDecl(PD);
PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ PD->setHasInheritedDefaultArg(Record[Idx++]);
}
void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) {
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index eed3cc1a5b3d..c256b4103a7d 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -565,7 +565,7 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(EXT_VECTOR_DECLS);
RECORD(COMMENT_RANGES);
RECORD(VERSION_CONTROL_BRANCH_REVISION);
-
+
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY);
@@ -710,24 +710,17 @@ void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
llvm::sys::Path MainFilePath(MainFile->getName());
- std::string MainFileName;
- if (!MainFilePath.isAbsolute()) {
- llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
- P.appendComponent(MainFilePath.str());
- MainFileName = P.str();
- } else {
- MainFileName = MainFilePath.str();
- }
+ MainFilePath.makeAbsolute();
- const char *MainFileNameStr = MainFileName.c_str();
+ const char *MainFileNameStr = MainFilePath.c_str();
MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
isysroot);
RecordData Record;
Record.push_back(pch::ORIGINAL_FILE_NAME);
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
}
-
+
// Repository branch/version information.
BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev();
RepoAbbrev->Add(BitCodeAbbrevOp(pch::VERSION_CONTROL_BRANCH_REVISION));
@@ -758,9 +751,9 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled.
Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled.
- Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C
+ Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C
// modern abi enabled.
- Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced
+ Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced
// modern abi enabled.
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
@@ -1048,7 +1041,7 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
for (unsigned I = 1, N = SourceMgr.sloc_entry_size(); I != N; ++I) {
// Get this source location entry.
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I);
-
+
// Record the offset of this source-location entry.
SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
@@ -1079,13 +1072,8 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// 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));
- std::string FilenameStr;
- if (!FilePath.isAbsolute()) {
- llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
- P.appendComponent(FilePath.str());
- FilenameStr = P.str();
- Filename = FilenameStr.c_str();
- }
+ FilePath.makeAbsolute();
+ Filename = FilePath.c_str();
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename);
@@ -1101,7 +1089,8 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// We add one to the size so that we capture the trailing NULL
// that is required by llvm::MemoryBuffer::getMemBuffer (on
// the reader side).
- const llvm::MemoryBuffer *Buffer = Content->getBuffer();
+ const llvm::MemoryBuffer *Buffer
+ = Content->getBuffer(PP.getDiagnostics());
const char *Name = Buffer->getBufferIdentifier();
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
llvm::StringRef(Name, strlen(Name) + 1));
@@ -1998,9 +1987,9 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Build a record containing all of the static unused functions in this file.
RecordData UnusedStaticFuncs;
- for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i)
+ for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i)
AddDeclRef(SemaRef.UnusedStaticFuncs[i], UnusedStaticFuncs);
-
+
// Build a record containing all of the locally-scoped external
// declarations in this header file. Generally, this record will be
// empty.
@@ -2063,7 +2052,7 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
WriteDecl(Context, DOT.getDecl());
}
Stream.ExitBlock();
-
+
WritePreprocessor(PP);
WriteMethodPool(SemaRef);
WriteIdentifierTable(PP);
@@ -2105,7 +2094,7 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Write the record containing unused static functions.
if (!UnusedStaticFuncs.empty())
Stream.EmitRecord(pch::UNUSED_STATIC_FUNCS, UnusedStaticFuncs);
-
+
// Write the record containing locally-scoped external definitions.
if (!LocallyScopedExternalDecls.empty())
Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS,
@@ -2206,7 +2195,7 @@ void PCHWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) {
AddTypeRef(TInfo->getType(), Record);
TypeLocWriter TLW(*this, Record);
for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
- TLW.Visit(TL);
+ TLW.Visit(TL);
}
void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
@@ -2227,14 +2216,14 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
ID = NextTypeID++;
DeclTypesToEmit.push(T);
}
-
+
// Encode the type qualifiers in the type reference.
Record.push_back((ID << Qualifiers::FastWidth) | FastQuals);
return;
}
assert(!T.hasLocalQualifiers());
-
+
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) {
pch::TypeID ID = 0;
switch (BT->getKind()) {
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 0774797463e0..7917280295ad 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -127,9 +127,10 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
Record.push_back(D->isDefinition());
Record.push_back(D->isEmbeddedInDeclarator());
- Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
Writer.AddSourceLocation(D->getRBraceLoc(), Record);
Writer.AddSourceLocation(D->getTagKeywordLoc(), Record);
+ // FIXME: maybe write optional qualifier and its range.
+ Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
}
void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
@@ -165,6 +166,7 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
VisitValueDecl(D);
Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ // FIXME: write optional qualifier and its range.
}
void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
@@ -398,6 +400,7 @@ void PCHDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
VisitVarDecl(D);
Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding
+ Record.push_back(D->hasInheritedDefaultArg());
Code = pch::DECL_PARM_VAR;
@@ -412,7 +415,8 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
D->getPCHLevel() == 0 &&
D->getStorageClass() == 0 &&
!D->hasCXXDirectInitializer() && // Can params have this ever?
- D->getObjCDeclQualifier() == 0)
+ D->getObjCDeclQualifier() == 0 &&
+ !D->hasInheritedDefaultArg())
AbbrevToUse = Writer.getParmVarDeclAbbrev();
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
@@ -496,6 +500,7 @@ void PCHWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
// ParmVarDecl
Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier
+ Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg
ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv);
}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index be5bb0dade87..44e0e1390604 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -61,7 +61,7 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace())
OS << ' ';
- llvm::SmallVector<char, 128> SpellingBuffer;
+ llvm::SmallString<128> SpellingBuffer;
for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end();
I != E; ++I) {
if (I->hasLeadingSpace())
diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp
index 0bcbd4ff0ee4..954e8e23cac7 100644
--- a/lib/Frontend/RewriteMacros.cpp
+++ b/lib/Frontend/RewriteMacros.cpp
@@ -79,7 +79,7 @@ static void LexRawTokensFromMainFile(Preprocessor &PP,
// up the indentifier info. This is important for equality comparison of
// identifier tokens.
if (RawTok.is(tok::identifier) && !RawTok.getIdentifierInfo())
- RawTok.setIdentifierInfo(PP.LookUpIdentifierInfo(RawTok));
+ PP.LookUpIdentifierInfo(RawTok);
RawTokens.push_back(RawTok);
} while (RawTok.isNot(tok::eof));
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 378b4225c53e..79aecceb70d0 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -89,6 +89,7 @@ namespace {
FunctionDecl *MsgSendFpretFunctionDecl;
FunctionDecl *GetClassFunctionDecl;
FunctionDecl *GetMetaClassFunctionDecl;
+ FunctionDecl *GetSuperClassFunctionDecl;
FunctionDecl *SelGetUidFunctionDecl;
FunctionDecl *CFStringFunctionDecl;
FunctionDecl *SuperContructorFunctionDecl;
@@ -133,7 +134,8 @@ namespace {
llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet;
llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo;
llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
-
+ llvm::SmallPtrSet<VarDecl *, 8> ImportedLocalExternalDecls;
+
llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
// This maps a property to it's assignment statement.
@@ -271,7 +273,7 @@ namespace {
void RewriteTypeOfDecl(VarDecl *VD);
void RewriteObjCQualifiedInterfaceTypes(Expr *E);
bool needToScanForQualifiers(QualType T);
- ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr);
+ bool isSuperReceiver(Expr *recExpr);
QualType getSuperStructType();
QualType getConstantStringStructType();
bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf);
@@ -323,6 +325,7 @@ namespace {
void SynthMsgSendSuperStretFunctionDecl();
void SynthGetClassFunctionDecl();
void SynthGetMetaClassFunctionDecl();
+ void SynthGetSuperClassFunctionDecl();
void SynthSelGetUidFunctionDecl();
void SynthSuperContructorFunctionDecl();
@@ -370,6 +373,7 @@ namespace {
void RewriteByRefVar(VarDecl *VD);
std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag);
Stmt *RewriteBlockDeclRefExpr(Expr *VD);
+ Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE);
void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
@@ -510,6 +514,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
MsgSendFpretFunctionDecl = 0;
GetClassFunctionDecl = 0;
GetMetaClassFunctionDecl = 0;
+ GetSuperClassFunctionDecl = 0;
SelGetUidFunctionDecl = 0;
CFStringFunctionDecl = 0;
ConstantStringClassReference = 0;
@@ -572,6 +577,8 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";
Preamble += "(const char *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass";
+ Preamble += "(struct objc_class *);\n";
Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";
Preamble += "(const char *);\n";
Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n";
@@ -699,9 +706,9 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
void RewriteObjC::RewriteInclude() {
SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID);
- std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
- const char *MainBufStart = MainBuf.first;
- const char *MainBufEnd = MainBuf.second;
+ llvm::StringRef MainBuf = SM->getBufferData(MainFileID);
+ const char *MainBufStart = MainBuf.begin();
+ const char *MainBufEnd = MainBuf.end();
size_t ImportLen = strlen("import");
// Loop over the whole file, looking for includes.
@@ -724,9 +731,9 @@ void RewriteObjC::RewriteInclude() {
}
void RewriteObjC::RewriteTabs() {
- std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
- const char *MainBufStart = MainBuf.first;
- const char *MainBufEnd = MainBuf.second;
+ llvm::StringRef MainBuf = SM->getBufferData(MainFileID);
+ const char *MainBufStart = MainBuf.begin();
+ const char *MainBufEnd = MainBuf.end();
// Loop over the whole file, looking for tabs.
for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
@@ -966,8 +973,6 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
}
void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
- std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
-
SourceLocation LocStart = PDecl->getLocStart();
// FIXME: handle protocol headers that are declared across multiple lines.
@@ -2491,6 +2496,23 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
FunctionDecl::Extern, false);
}
+// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
+void RewriteObjC::SynthGetSuperClassFunctionDecl() {
+ IdentifierInfo *getSuperClassIdent =
+ &Context->Idents.get("class_getSuperclass");
+ llvm::SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(Context->getObjCClassType());
+ QualType getClassType = Context->getFunctionType(Context->getObjCClassType(),
+ &ArgTys[0], ArgTys.size(),
+ false /*isVariadic*/, 0,
+ false, false, 0, 0, false,
+ CC_Default);
+ GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ getSuperClassIdent, getClassType, 0,
+ FunctionDecl::Extern, false);
+}
+
// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
void RewriteObjC::SynthGetMetaClassFunctionDecl() {
IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
@@ -2551,18 +2573,10 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
return cast;
}
-ObjCInterfaceDecl *RewriteObjC::isSuperReceiver(Expr *recExpr) {
+bool RewriteObjC::isSuperReceiver(Expr *recExpr) {
// check if we are sending a message to 'super'
- if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return 0;
-
- if (ObjCSuperExpr *Super = dyn_cast<ObjCSuperExpr>(recExpr)) {
- const ObjCObjectPointerType *OPT =
- Super->getType()->getAs<ObjCObjectPointerType>();
- assert(OPT);
- const ObjCInterfaceType *IT = OPT->getInterfaceType();
- return IT->getDecl();
- }
- return 0;
+ if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return false;
+ return isa<ObjCSuperExpr>(recExpr);
}
// struct objc_super { struct objc_object *receiver; struct objc_class *super; };
@@ -2640,6 +2654,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SynthMsgSendFpretFunctionDecl();
if (!GetClassFunctionDecl)
SynthGetClassFunctionDecl();
+ if (!GetSuperClassFunctionDecl)
+ SynthGetSuperClassFunctionDecl();
if (!GetMetaClassFunctionDecl)
SynthGetMetaClassFunctionDecl();
@@ -2669,8 +2685,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
- ObjCInterfaceDecl *SuperDecl =
- CurMethodDef->getClassInterface()->getSuperClass();
+ ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
llvm::SmallVector<Expr*, 4> InitExprs;
@@ -2683,19 +2698,31 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation()))
); // set the 'receiver'.
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
- SuperDecl->getIdentifier()->getNameStart(),
- SuperDecl->getIdentifier()->getLength(),
+ ClassDecl->getIdentifier()->getNameStart(),
+ ClassDecl->getIdentifier()->getLength(),
false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
StartLoc,
EndLoc);
+ // (Class)objc_getClass("CurrentClass")
+ CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCClassType(),
+ CastExpr::CK_Unknown, Cls);
+ ClsExprs.clear();
+ ClsExprs.push_back(ArgExpr);
+ Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
+ &ClsExprs[0], ClsExprs.size(),
+ StartLoc, EndLoc);
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
// To turn off a warning, type-cast to 'id'
- InitExprs.push_back( // set 'super class', using objc_getClass().
+ InitExprs.push_back( // set 'super class', using class_getSuperclass().
NoTypeInfoCStyleCastExpr(Context,
Context->getObjCIdType(),
CastExpr::CK_Unknown, Cls));
@@ -2755,12 +2782,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
} else { // instance message.
Expr *recExpr = Exp->getReceiver();
- if (ObjCInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) {
+ if (isSuperReceiver(recExpr)) {
MsgSendFlavor = MsgSendSuperFunctionDecl;
if (MsgSendStretFlavor)
MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
-
+ ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
llvm::SmallVector<Expr*, 4> InitExprs;
InitExprs.push_back(
@@ -2770,20 +2797,32 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
Context->getObjCIdType(),
SourceLocation()))
); // set the 'receiver'.
-
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
- SuperDecl->getIdentifier()->getNameStart(),
- SuperDecl->getIdentifier()->getLength(),
+ ClassDecl->getIdentifier()->getNameStart(),
+ ClassDecl->getIdentifier()->getLength(),
false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
StartLoc, EndLoc);
+ // (Class)objc_getClass("CurrentClass")
+ CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCClassType(),
+ CastExpr::CK_Unknown, Cls);
+ ClsExprs.clear();
+ ClsExprs.push_back(ArgExpr);
+ Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
+ &ClsExprs[0], ClsExprs.size(),
+ StartLoc, EndLoc);
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
// To turn off a warning, type-cast to 'id'
InitExprs.push_back(
- // set 'super class', using objc_getClass().
+ // set 'super class', using class_getSuperclass().
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CastExpr::CK_Unknown, Cls));
// struct objc_super
@@ -3986,6 +4025,12 @@ void RewriteObjC::RewriteByRefString(std::string &ResultStr,
"_" + utostr(BlockByRefDeclNo[VD]) ;
}
+static bool HasLocalVariableExternalStorage(ValueDecl *VD) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(VD))
+ return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage());
+ return false;
+}
+
std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
const char *funcName,
std::string Tag) {
@@ -4060,7 +4105,10 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
}
else {
std::string Name = (*I)->getNameAsString();
- (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy);
+ QualType QT = (*I)->getType();
+ if (HasLocalVariableExternalStorage(*I))
+ QT = Context->getPointerType(QT);
+ QT.getAsStringInternal(Name, Context->PrintingPolicy);
S += Name + " = __cself->" +
(*I)->getNameAsString() + "; // bound by copy\n";
}
@@ -4149,8 +4197,11 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += "struct __block_impl *";
Constructor += ", void *" + ArgName;
} else {
- (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy);
- (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy);
+ QualType QT = (*I)->getType();
+ if (HasLocalVariableExternalStorage(*I))
+ QT = Context->getPointerType(QT);
+ QT.getAsStringInternal(FieldName, Context->PrintingPolicy);
+ QT.getAsStringInternal(ArgName, Context->PrintingPolicy);
Constructor += ", " + ArgName;
}
S += FieldName + ";\n";
@@ -4380,10 +4431,19 @@ void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {
GetBlockDeclRefExprs(*CI);
}
// Handle specific things.
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S))
+ if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) {
// FIXME: Handle enums.
if (!isa<FunctionDecl>(CDRE->getDecl()))
BlockDeclRefs.push_back(CDRE);
+ }
+ else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S))
+ if (HasLocalVariableExternalStorage(DRE->getDecl())) {
+ BlockDeclRefExpr *BDRE =
+ new (Context)BlockDeclRefExpr(DRE->getDecl(), DRE->getType(),
+ DRE->getLocation(), false);
+ BlockDeclRefs.push_back(BDRE);
+ }
+
return;
}
@@ -4406,10 +4466,16 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
}
// Handle specific things.
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S))
+ if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) {
if (!isa<FunctionDecl>(CDRE->getDecl()) &&
!InnerContexts.count(CDRE->getDecl()->getDeclContext()))
InnerBlockDeclRefs.push_back(CDRE);
+ }
+ else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (Var->isFunctionOrMethodVarDecl())
+ ImportedLocalExternalDecls.insert(Var);
+ }
return;
}
@@ -4572,6 +4638,23 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
return PE;
}
+// Rewrites the imported local variable V with external storage
+// (static, extern, etc.) as *V
+//
+Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VarDecl *Var = dyn_cast<VarDecl>(VD))
+ if (!ImportedLocalExternalDecls.count(Var))
+ return DRE;
+ Expr *Exp = new (Context) UnaryOperator(DRE, UnaryOperator::Deref,
+ DRE->getType(), DRE->getLocation());
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ Exp);
+ ReplaceStmt(DRE, PE);
+ return PE;
+}
+
void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
SourceLocation LocStart = CE->getLParenLoc();
SourceLocation LocEnd = CE->getRParenLoc();
@@ -5091,6 +5174,13 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
} else {
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ if (HasLocalVariableExternalStorage(*I)) {
+ QualType QT = (*I)->getType();
+ QT = Context->getPointerType(QT);
+ Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, QT,
+ SourceLocation());
+ }
+
}
InitExprs.push_back(Exp);
}
@@ -5205,11 +5295,12 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
llvm::SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs;
llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts;
InnerContexts.insert(BE->getBlockDecl());
+ ImportedLocalExternalDecls.clear();
GetInnerBlockDeclRefExprs(BE->getBody(),
InnerBlockDeclRefs, InnerContexts);
// Rewrite the block body in place.
RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
-
+ ImportedLocalExternalDecls.clear();
// Now we snarf the rewritten text and stash it away for later use.
std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
RewrittenBlockExprs[BE] = Str;
@@ -5392,6 +5483,8 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
ValueDecl *VD = DRE->getDecl();
if (VD->hasAttr<BlocksAttr>())
return RewriteBlockDeclRefExpr(DRE);
+ if (HasLocalVariableExternalStorage(VD))
+ return RewriteLocalVariableExternalStorage(DRE);
}
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index d2aa5480b4b1..24d51e2c78dc 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -119,19 +119,19 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
}
assert(StartColNo <= EndColNo && "Invalid range!");
-
+
// Pick the first non-whitespace column.
while (StartColNo < SourceLine.size() &&
(SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
++StartColNo;
-
+
// Pick the last non-whitespace column.
if (EndColNo > SourceLine.size())
EndColNo = SourceLine.size();
while (EndColNo-1 &&
(SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
--EndColNo;
-
+
// If the start/end passed each other, then we are trying to highlight a range
// that just exists in whitespace, which must be some sort of other bug.
assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
@@ -300,10 +300,10 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E);
Ranges[i] = SourceRange(S, E);
}
-
+
// Get the pretty name, according to #line directives etc.
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
-
+
// If this diagnostic is not in the main file, print out the "included from"
// lines.
if (LastWarningLoc != PLoc.getIncludeLoc()) {
@@ -330,8 +330,10 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
unsigned FileOffset = LocInfo.second;
// Get information about the buffer it points into.
- std::pair<const char*, const char*> BufferInfo = SM.getBufferData(FID);
- const char *BufStart = BufferInfo.first;
+ bool Invalid = false;
+ const char *BufStart = SM.getBufferData(FID, &Invalid).data();
+ if (Invalid)
+ return;
unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
unsigned CaretEndColNo
@@ -563,7 +565,7 @@ static unsigned findEndOfWord(unsigned Start,
// We have the start of a balanced punctuation sequence (quotes,
// parentheses, etc.). Determine the full sequence is.
- llvm::SmallVector<char, 16> PunctuationEndStack;
+ llvm::SmallString<16> PunctuationEndStack;
PunctuationEndStack.push_back(EndPunct);
while (End < Length && !PunctuationEndStack.empty()) {
if (Str[End] == PunctuationEndStack.back())
@@ -704,7 +706,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
if (DiagOpts->ShowLocation) {
if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
-
+
// Emit a Visual Studio compatible line number syntax.
if (LangOpts && LangOpts->Microsoft) {
OS << PLoc.getFilename() << '(' << LineNo << ')';
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index b3bdac68855e..972b2e0d3038 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -199,6 +199,143 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/* Extract a float from X at index N into the first index of the return. */
#define _MM_PICK_OUT_PS(X, N) _mm_insert_ps (_mm_setzero_ps(), (X), \
_MM_MK_INSERTPS_NDX((N), 0, 0x0e))
+
+/* Insert int into packed integer array at index. */
+#define _mm_insert_epi8(X, I, N) (__extension__ ({ __v16qi __a = (__v16qi)X; \
+ __a[N] = I; \
+ __a;}))
+#define _mm_insert_epi32(X, I, N) (__extension__ ({ __v4si __a = (__v4si)X; \
+ __a[N] = I; \
+ __a;}))
+#ifdef __x86_64__
+#define _mm_insert_epi64(X, I, N) (__extension__ ({ __v2di __a = (__v2di)X; \
+ __a[N] = I; \
+ __a;}))
+#endif /* __x86_64__ */
+
+/* Extract int from packed integer array at index. */
+#define _mm_extract_epi8(X, N) (__extension__ ({ __v16qi __a = (__v16qi)X; \
+ __a[N];}))
+#define _mm_extract_epi32(X, N) (__extension__ ({ __v4si __a = (__v4si)X; \
+ __a[N];}))
+#ifdef __x86_64__
+#define _mm_extract_epi64(X, N) (__extension__ ({ __v2di __a = (__v2di)X; \
+ __a[N];}))
+#endif /* __x86_64 */
+
+/* SSE4 128-bit Packed Integer Comparisons. */
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_testz_si128(__m128i __M, __m128i __V)
+{
+ return __builtin_ia32_ptestz128((__v2di)__M, (__v2di)__V);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_testc_si128(__m128i __M, __m128i __V)
+{
+ return __builtin_ia32_ptestc128((__v2di)__M, (__v2di)__V);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_testnzc_si128(__m128i __M, __m128i __V)
+{
+ return __builtin_ia32_ptestnzc128((__v2di)__M, (__v2di)__V);
+}
+
+#define _mm_test_all_ones(V) _mm_testc_si128((V), _mm_cmpeq_epi32((V), (V)))
+#define _mm_test_mix_ones_zeros(M, V) _mm_testnzc_si128((M), (V))
+#define _mm_test_all_zeros(M, V) _mm_testz_si128 ((V), (V))
+
+/* SSE4 64-bit Packed Integer Comparisons. */
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_epi64(__m128i __V1, __m128i __V2)
+{
+ return (__m128i) __builtin_ia32_pcmpeqq((__v2di)__V1, (__v2di)__V2);
+}
+
+/* SSE4 Packed Integer Sign-Extension. */
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepi8_epi16(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovsxbw128((__v16qi) __V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepi8_epi32(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovsxbd128((__v16qi) __V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepi8_epi64(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovsxbq128((__v16qi) __V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepi16_epi32(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovsxwd128((__v8hi) __V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepi16_epi64(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovsxwq128((__v8hi)__V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepi32_epi64(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovsxdq128((__v4si)__V);
+}
+
+/* SSE4 Packed Integer Zero-Extension. */
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepu8_epi16(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovzxbw128((__v16qi) __V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepu8_epi32(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovzxbd128((__v16qi)__V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepu8_epi64(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovzxbq128((__v16qi)__V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepu16_epi32(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovzxwd128((__v8hi)__V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepu16_epi64(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovzxwq128((__v8hi)__V);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepu32_epi64(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_pmovzxdq128((__v4si)__V);
+}
+
+/* SSE4 Pack with Unsigned Saturation. */
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_packus_epi32(__m128i __V1, __m128i __V2)
+{
+ return (__m128i) __builtin_ia32_packusdw128((__v4si)__V1, (__v4si)__V2);
+}
+
+/* SSE4 Multiple Packed Sums of Absolute Difference. */
+#define _mm_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw128((X), (Y), (M))
#endif /* __SSE4_1__ */
diff --git a/lib/Index/Entity.cpp b/lib/Index/Entity.cpp
index 03fe9f73af40..cd9d277bb6cb 100644
--- a/lib/Index/Entity.cpp
+++ b/lib/Index/Entity.cpp
@@ -71,9 +71,7 @@ Entity EntityGetter::VisitNamedDecl(NamedDecl *D) {
DeclarationName GlobName;
if (IdentifierInfo *II = LocalName.getAsIdentifierInfo()) {
- IdentifierInfo *GlobII =
- &ProgImpl.getIdents().get(II->getNameStart(),
- II->getNameStart() + II->getLength());
+ IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName());
GlobName = DeclarationName(GlobII);
} else {
Selector LocalSel = LocalName.getObjCSelector();
@@ -140,9 +138,7 @@ Decl *EntityImpl::getDecl(ASTContext &AST) {
DeclarationName LocalName;
if (IdentifierInfo *GlobII = Name.getAsIdentifierInfo()) {
- IdentifierInfo &II =
- AST.Idents.get(GlobII->getNameStart(),
- GlobII->getNameStart() + GlobII->getLength());
+ IdentifierInfo &II = AST.Idents.get(GlobII->getName());
LocalName = DeclarationName(&II);
} else {
Selector GlobSel = Name.getObjCSelector();
diff --git a/lib/Index/GlobalSelector.cpp b/lib/Index/GlobalSelector.cpp
index 2b2ca6d3b1cc..34679185b166 100644
--- a/lib/Index/GlobalSelector.cpp
+++ b/lib/Index/GlobalSelector.cpp
@@ -29,9 +29,7 @@ Selector GlobalSelector::getSelector(ASTContext &AST) const {
for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs();
i != e; ++i) {
IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i);
- IdentifierInfo *II =
- &AST.Idents.get(GlobII->getNameStart(),
- GlobII->getNameStart() + GlobII->getLength());
+ IdentifierInfo *II = &AST.Idents.get(GlobII->getName());
Ids.push_back(II);
}
@@ -58,9 +56,7 @@ GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) {
for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs();
i != e; ++i) {
IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i);
- IdentifierInfo *GlobII =
- &ProgImpl.getIdents().get(II->getNameStart(),
- II->getNameStart() + II->getLength());
+ IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName());
Ids.push_back(GlobII);
}
diff --git a/lib/Index/Makefile b/lib/Index/Makefile
index 9d33a2d175e3..4d8671361cdf 100644
--- a/lib/Index/Makefile
+++ b/lib/Index/Makefile
@@ -18,10 +18,10 @@ LIBRARYNAME := clangIndex
BUILD_ARCHIVE = 1
ifeq ($(ARCH),PowerPC)
-CXXFLAGS += -maltivec
+CXX.Flags += -maltivec
endif
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 3207062ccadd..6cdb96f37de4 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -229,14 +229,18 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
// the token this macro expanded to.
Loc = SM.getInstantiationLoc(Loc);
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
- std::pair<const char *,const char *> Buffer = SM.getBufferData(LocInfo.first);
- const char *StrData = Buffer.first+LocInfo.second;
+ bool Invalid = false;
+ llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return 0;
+
+ const char *StrData = Buffer.data()+LocInfo.second;
if (isWhitespace(StrData[0]))
return 0;
// Create a lexer starting at the beginning of this token.
- Lexer TheLexer(Loc, LangOpts, Buffer.first, StrData, Buffer.second);
+ Lexer TheLexer(Loc, LangOpts, Buffer.begin(), StrData, Buffer.end());
TheLexer.SetCommentRetentionState(true);
Token TheTok;
TheLexer.LexFromRawLexer(TheTok);
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 004e6755e5f5..1cfa0e374506 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -806,7 +806,14 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
// Get the spelling of the token, which eliminates trigraphs, etc. We know
// that ThisTokBuf points to a buffer that is big enough for the whole token
// and 'spelled' tokens can only shrink.
- unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf);
+ bool StringInvalid = false;
+ unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf,
+ &StringInvalid);
+ if (StringInvalid) {
+ hadError = 1;
+ continue;
+ }
+
const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote.
// TODO: Input character set mapping support.
@@ -904,8 +911,12 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
llvm::SmallString<16> SpellingBuffer;
SpellingBuffer.resize(Tok.getLength());
+ bool StringInvalid = false;
const char *SpellingPtr = &SpellingBuffer[0];
- unsigned TokLen = PP.getSpelling(Tok, SpellingPtr);
+ unsigned TokLen = PP.getSpelling(Tok, SpellingPtr, &StringInvalid);
+ if (StringInvalid) {
+ return 0;
+ }
assert(SpellingPtr[0] != 'L' && "Doesn't handle wide strings yet");
diff --git a/lib/Lex/Makefile b/lib/Lex/Makefile
index 509077017c2d..bd3c7a872d3a 100644
--- a/lib/Lex/Makefile
+++ b/lib/Lex/Makefile
@@ -18,10 +18,10 @@ LIBRARYNAME := clangLex
BUILD_ARCHIVE = 1
ifeq ($(ARCH),PowerPC)
-CXXFLAGS += -maltivec
+CXX.Flags += -maltivec
endif
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 976c94eda364..cddc6cff727a 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -471,7 +471,7 @@ void Preprocessor::HandleDirective(Token &Result) {
CurPPLexer->ParsingPreprocessorDirective = true;
++NumDirectives;
-
+
// We are about to read a token. For the multiple-include optimization FA to
// work, we have to remember if we had read any tokens *before* this
// pp-directive.
@@ -964,7 +964,7 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
/// false if the > was found, otherwise it returns true if it finds and consumes
/// the EOM marker.
bool Preprocessor::ConcatenateIncludeName(
- llvm::SmallVector<char, 128> &FilenameBuffer) {
+ llvm::SmallString<128> &FilenameBuffer) {
Token CurTok;
Lex(CurTok);
@@ -1042,7 +1042,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
return;
}
- bool isAngled =
+ bool isAngled =
GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
@@ -1070,7 +1070,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
-
+
// Ask HeaderInfo if we should enter this #include file. If not, #including
// this file will have no effect.
if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport))
@@ -1512,7 +1512,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
MacroInfo *MI = getMacroInfo(MII);
-
+
if (CurPPLexer->getConditionalStackDepth() == 0) {
// If the start of a top-level #ifdef and if the macro is not defined,
// inform MIOpt that this might be the start of a proper include guard.
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index ede129edcb6f..756ce27a93dc 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -170,7 +170,12 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
return true;
case tok::numeric_constant: {
llvm::SmallString<64> IntegerBuffer;
- llvm::StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer);
+ bool NumberInvalid = false;
+ llvm::StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer,
+ &NumberInvalid);
+ if (NumberInvalid)
+ return true; // a diagnostic was already reported
+
NumericLiteralParser Literal(Spelling.begin(), Spelling.end(),
PeekTok.getLocation(), PP);
if (Literal.hadError)
@@ -216,7 +221,10 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
}
case tok::char_constant: { // 'x'
llvm::SmallString<32> CharBuffer;
- llvm::StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer);
+ bool CharInvalid = false;
+ llvm::StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid);
+ if (CharInvalid)
+ return true;
CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(),
PeekTok.getLocation(), PP);
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 0b26ccbecbab..81e6bf809025 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -80,9 +80,8 @@ 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, &ErrorStr);
- if (!ErrorStr.empty())
+ const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID);
+ if (!InputFile)
return true;
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index a64008ab1806..3b949d0ab40a 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -549,12 +549,12 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) {
return II;
}
-IdentifierInfo* PTHManager::get(const char *NameStart, const char *NameEnd) {
+IdentifierInfo* PTHManager::get(llvm::StringRef Name) {
PTHStringIdLookup& SL = *((PTHStringIdLookup*)StringIdLookup);
// Double check our assumption that the last character isn't '\0'.
- assert(NameEnd==NameStart || NameStart[NameEnd-NameStart-1] != '\0');
- PTHStringIdLookup::iterator I = SL.find(std::make_pair(NameStart,
- NameEnd - NameStart));
+ assert(Name.empty() || Name.data()[Name.size()-1] != '\0');
+ PTHStringIdLookup::iterator I = SL.find(std::make_pair(Name.data(),
+ Name.size()));
if (I == SL.end()) // No identifier found?
return 0;
@@ -662,7 +662,7 @@ public:
CacheTy::iterator I = Cache.find(path);
// If we don't get a hit in the PTH file just forward to 'stat'.
- if (I == Cache.end())
+ if (I == Cache.end())
return StatSysCallCache::stat(path, buf);
const PTHStatData& Data = *I;
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 2c6ad6ee462c..5584b18da15f 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -52,7 +52,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
bool OwnsHeaders)
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0),
- Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0),
+ Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0),
CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0) {
ScratchBuf = new ScratchBuffer(SourceMgr);
CounterValue = 0; // __COUNTER__ starts at 0.
@@ -80,7 +80,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
// We haven't read anything from the external source.
ReadMacrosFromExternalSource = false;
-
+
// "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
// This gets unpoisoned where it is allowed.
(Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
@@ -116,7 +116,7 @@ Preprocessor::~Preprocessor() {
// Free any cached macro expanders.
for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i)
delete TokenLexerCache[i];
-
+
// Free any cached MacroArgs.
for (MacroArgs *ArgList = MacroArgCache; ArgList; )
ArgList = ArgList->deallocate();
@@ -198,30 +198,30 @@ void Preprocessor::PrintStats() {
<< NumFastTokenPaste << " on the fast path.\n";
}
-Preprocessor::macro_iterator
-Preprocessor::macro_begin(bool IncludeExternalMacros) const {
- if (IncludeExternalMacros && ExternalSource &&
+Preprocessor::macro_iterator
+Preprocessor::macro_begin(bool IncludeExternalMacros) const {
+ if (IncludeExternalMacros && ExternalSource &&
!ReadMacrosFromExternalSource) {
ReadMacrosFromExternalSource = true;
ExternalSource->ReadDefinedMacros();
}
-
- return Macros.begin();
+
+ return Macros.begin();
}
-Preprocessor::macro_iterator
-Preprocessor::macro_end(bool IncludeExternalMacros) const {
- if (IncludeExternalMacros && ExternalSource &&
+Preprocessor::macro_iterator
+Preprocessor::macro_end(bool IncludeExternalMacros) const {
+ if (IncludeExternalMacros && ExternalSource &&
!ReadMacrosFromExternalSource) {
ReadMacrosFromExternalSource = true;
ExternalSource->ReadDefinedMacros();
}
-
- return Macros.end();
+
+ return Macros.end();
}
-bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
- unsigned TruncateAtLine,
+bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
+ unsigned TruncateAtLine,
unsigned TruncateAtColumn) {
using llvm::MemoryBuffer;
@@ -242,7 +242,7 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
for (; *Position; ++Position) {
if (*Position != '\r' && *Position != '\n')
continue;
-
+
// Eat \r\n or \n\r as a single line.
if ((Position[1] == '\r' || Position[1] == '\n') &&
Position[0] != Position[1])
@@ -251,13 +251,13 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
break;
}
}
-
+
Position += TruncateAtColumn - 1;
-
+
// Truncate the buffer.
if (Position < Buffer->getBufferEnd()) {
- MemoryBuffer *TruncatedBuffer
- = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position,
+ MemoryBuffer *TruncatedBuffer
+ = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position,
Buffer->getBufferIdentifier());
SourceMgr.overrideFileContents(File, TruncatedBuffer);
}
@@ -282,11 +282,19 @@ bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const {
/// UCNs, etc.
std::string Preprocessor::getSpelling(const Token &Tok,
const SourceManager &SourceMgr,
- const LangOptions &Features) {
+ const LangOptions &Features,
+ bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
// If this token contains nothing interesting, return it directly.
- const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation());
+ bool CharDataInvalid = false;
+ const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation(),
+ &CharDataInvalid);
+ if (Invalid)
+ *Invalid = CharDataInvalid;
+ if (CharDataInvalid)
+ return std::string();
+
if (!Tok.needsCleaning())
return std::string(TokStart, TokStart+Tok.getLength());
@@ -310,8 +318,8 @@ std::string Preprocessor::getSpelling(const Token &Tok,
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
-std::string Preprocessor::getSpelling(const Token &Tok) const {
- return getSpelling(Tok, SourceMgr, Features);
+std::string Preprocessor::getSpelling(const Token &Tok, bool *Invalid) const {
+ return getSpelling(Tok, SourceMgr, Features, Invalid);
}
/// getSpelling - This method is used to get the spelling of a token into a
@@ -325,7 +333,7 @@ std::string Preprocessor::getSpelling(const Token &Tok) const {
/// copy). The caller is not allowed to modify the returned buffer pointer
/// if an internal buffer is returned.
unsigned Preprocessor::getSpelling(const Token &Tok,
- const char *&Buffer) const {
+ const char *&Buffer, bool *Invalid) const {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
// If this token is an identifier, just return the string from the identifier
@@ -341,8 +349,16 @@ unsigned Preprocessor::getSpelling(const Token &Tok,
if (Tok.isLiteral())
TokStart = Tok.getLiteralData();
- if (TokStart == 0)
- TokStart = SourceMgr.getCharacterData(Tok.getLocation());
+ if (TokStart == 0) {
+ bool CharDataInvalid = false;
+ TokStart = SourceMgr.getCharacterData(Tok.getLocation(), &CharDataInvalid);
+ if (Invalid)
+ *Invalid = CharDataInvalid;
+ if (CharDataInvalid) {
+ Buffer = "";
+ return 0;
+ }
+ }
// If this token contains nothing interesting, return it directly.
if (!Tok.needsCleaning()) {
@@ -368,7 +384,8 @@ unsigned Preprocessor::getSpelling(const Token &Tok,
/// SmallVector. Note that the returned StringRef may not point to the
/// supplied buffer if a copy can be avoided.
llvm::StringRef Preprocessor::getSpelling(const Token &Tok,
- llvm::SmallVectorImpl<char> &Buffer) const {
+ llvm::SmallVectorImpl<char> &Buffer,
+ bool *Invalid) const {
// Try the fast path.
if (const IdentifierInfo *II = Tok.getIdentifierInfo())
return II->getName();
@@ -378,7 +395,7 @@ llvm::StringRef Preprocessor::getSpelling(const Token &Tok,
Buffer.resize(Tok.getLength());
const char *Ptr = Buffer.data();
- unsigned Len = getSpelling(Tok, Ptr);
+ unsigned Len = getSpelling(Tok, Ptr, Invalid);
return llvm::StringRef(Ptr, Len);
}
@@ -446,7 +463,7 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart,
return TokStart.getFileLocWithOffset(PhysOffset);
}
-SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc,
+SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc,
unsigned Offset) {
if (Loc.isInvalid() || !Loc.isFileID())
return SourceLocation();
@@ -456,7 +473,7 @@ SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc,
Len = Len - Offset;
else
return Loc;
-
+
return AdvanceToTokenCharacter(Loc, Len);
}
@@ -519,7 +536,7 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier,
II = getIdentifierInfo(llvm::StringRef(BufPtr, Identifier.getLength()));
} else {
// Cleaning needed, alloca a buffer, clean into it, then use the buffer.
- llvm::SmallVector<char, 64> IdentifierBuffer;
+ llvm::SmallString<64> IdentifierBuffer;
llvm::StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer);
II = getIdentifierInfo(CleanedStr);
}
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 5d95eb39c89e..dbd1b8400de3 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -325,7 +325,7 @@ void TokenLexer::Lex(Token &Tok) {
// returned by PasteTokens, not the pasted token.
if (PasteTokens(Tok))
return;
-
+
TokenIsFromPaste = true;
}
@@ -379,7 +379,7 @@ void TokenLexer::Lex(Token &Tok) {
/// are more ## after it, chomp them iteratively. Return the result as Tok.
/// If this returns true, the caller should immediately return the token.
bool TokenLexer::PasteTokens(Token &Tok) {
- llvm::SmallVector<char, 128> Buffer;
+ llvm::SmallString<128> Buffer;
const char *ResultTokStrPtr = 0;
do {
// Consume the ## operator.
@@ -439,7 +439,11 @@ bool TokenLexer::PasteTokens(Token &Tok) {
SourceManager &SourceMgr = PP.getSourceManager();
FileID LocFileID = SourceMgr.getFileID(ResultTokLoc);
- const char *ScratchBufStart = SourceMgr.getBufferData(LocFileID).first;
+ bool Invalid = false;
+ const char *ScratchBufStart
+ = SourceMgr.getBufferData(LocFileID, &Invalid).data();
+ if (Invalid)
+ return false;
// Make a lexer to lex this string from. Lex just this one token.
// Make a lexer object so that we lex and expand the paste result.
@@ -506,8 +510,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
if (Tok.is(tok::identifier)) {
// Look up the identifier info for the token. We disabled identifier lookup
// by saying we're skipping contents, so we need to do this manually.
- IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok, ResultTokStrPtr);
- Tok.setIdentifierInfo(II);
+ PP.LookUpIdentifierInfo(Tok, ResultTokStrPtr);
}
return false;
}
diff --git a/lib/Parse/Makefile b/lib/Parse/Makefile
index de16e3ea665a..6a5540f73356 100644
--- a/lib/Parse/Makefile
+++ b/lib/Parse/Makefile
@@ -15,7 +15,7 @@ LEVEL = ../../../..
LIBRARYNAME := clangParse
BUILD_ARCHIVE = 1
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index bfb75d2dd3d4..b92e7539deda 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -52,7 +52,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
Actions.CodeCompleteNamespaceDecl(CurScope);
ConsumeToken();
}
-
+
SourceLocation IdentLoc;
IdentifierInfo *Ident = 0;
@@ -130,7 +130,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
Actions.CodeCompleteNamespaceAliasDecl(CurScope);
ConsumeToken();
}
-
+
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
@@ -165,7 +165,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
unsigned Context) {
assert(Tok.is(tok::string_literal) && "Not a string literal!");
- llvm::SmallVector<char, 8> LangBuffer;
+ llvm::SmallString<8> LangBuffer;
// LangBuffer is guaranteed to be big enough.
llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer);
@@ -183,7 +183,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
Attr = ParseCXX0XAttributes();
}
-
+
if (Tok.isNot(tok::l_brace)) {
ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList);
return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
@@ -222,7 +222,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
Actions.CodeCompleteUsing(CurScope);
ConsumeToken();
}
-
+
if (Tok.is(tok::kw_namespace))
// Next token after 'using' is 'namespace' so it must be using-directive
return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList);
@@ -259,7 +259,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
Actions.CodeCompleteUsingDirective(CurScope);
ConsumeToken();
}
-
+
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
@@ -332,20 +332,20 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
return DeclPtrTy();
}
- // Parse the unqualified-id. We allow parsing of both constructor and
+ // Parse the unqualified-id. We allow parsing of both constructor and
// destructor names and allow the action module to diagnose any semantic
// errors.
UnqualifiedId Name;
- if (ParseUnqualifiedId(SS,
+ if (ParseUnqualifiedId(SS,
/*EnteringContext=*/false,
/*AllowDestructorName=*/true,
- /*AllowConstructorName=*/true,
- /*ObjectType=*/0,
+ /*AllowConstructorName=*/true,
+ /*ObjectType=*/0,
Name)) {
SkipUntil(tok::semi);
return DeclPtrTy();
}
-
+
// Parse (optional) attributes (most likely GNU strong-using extension).
llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute))
@@ -354,7 +354,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
// Eat ';'.
DeclEnd = Tok.getLocation();
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
- AttrList ? "attributes list" : "using declaration",
+ AttrList ? "attributes list" : "using declaration",
tok::semi);
return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name,
@@ -502,26 +502,26 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
Diag(IdLoc, diag::err_unknown_template_name)
<< Id;
}
-
+
if (!Template)
return true;
- // Form the template name
+ // Form the template name
UnqualifiedId TemplateName;
TemplateName.setIdentifier(Id, IdLoc);
-
+
// Parse the full template-id, then turn it into a type.
if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
SourceLocation(), true))
return true;
if (TNK == TNK_Dependent_template_name)
AnnotateTemplateIdTokenAsType(SS);
-
+
// If we didn't end up with a typename token, there's nothing more we
// can do.
if (Tok.isNot(tok::annot_typename))
return true;
-
+
// Retrieve the type from the annotation token, consume that token, and
// return.
EndLocation = Tok.getAnnotationEndLoc();
@@ -532,7 +532,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
// We have an identifier; check whether it is actually a type.
TypeTy *Type = Actions.getTypeName(*Id, IdLoc, CurScope, SS, true);
- if (!Type) {
+ if (!Type) {
Diag(IdLoc, diag::err_expected_class_name);
return true;
}
@@ -601,7 +601,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Actions.CodeCompleteTag(CurScope, TagType);
ConsumeToken();
}
-
+
AttributeList *AttrList = 0;
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
@@ -610,7 +610,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// If declspecs exist after tag, parse them.
if (Tok.is(tok::kw___declspec))
AttrList = ParseMicrosoftDeclSpec(AttrList);
-
+
// If C++0x attributes exist here, parse them.
// FIXME: Are we consistent with the ordering of parsing of different
// styles of attributes?
@@ -642,7 +642,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (getLang().CPlusPlus) {
// "FOO : BAR" is not a potential typo for "FOO::BAR".
ColonProtectionRAIIObject X(*this);
-
+
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true);
if (SS.isSet())
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
@@ -658,21 +658,21 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
-
+
if (Tok.is(tok::less)) {
- // The name was supposed to refer to a template, but didn't.
+ // The name was supposed to refer to a template, but didn't.
// Eat the template argument list and try to continue parsing this as
// a class (or template thereof).
TemplateArgList TemplateArgs;
SourceLocation LAngleLoc, RAngleLoc;
- if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS,
+ if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS,
true, LAngleLoc,
TemplateArgs, RAngleLoc)) {
// We couldn't parse the template argument list at all, so don't
// try to give any location information for the list.
LAngleLoc = RAngleLoc = SourceLocation();
}
-
+
Diag(NameLoc, diag::err_explicit_spec_non_template)
<< (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
<< (TagType == DeclSpec::TST_class? 0
@@ -680,30 +680,30 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
: 2)
<< Name
<< SourceRange(LAngleLoc, RAngleLoc);
-
- // Strip off the last template parameter list if it was empty, since
+
+ // Strip off the last template parameter list if it was empty, since
// we've removed its template argument list.
if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) {
if (TemplateParams && TemplateParams->size() > 1) {
TemplateParams->pop_back();
} else {
TemplateParams = 0;
- const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
+ const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
= ParsedTemplateInfo::NonTemplate;
}
} else if (TemplateInfo.Kind
== ParsedTemplateInfo::ExplicitInstantiation) {
// Pretend this is just a forward declaration.
TemplateParams = 0;
- const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
+ const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
= ParsedTemplateInfo::NonTemplate;
- const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc
+ const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc
= SourceLocation();
const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc
= SourceLocation();
}
-
-
+
+
}
} else if (Tok.is(tok::annot_template_id)) {
TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
@@ -896,7 +896,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// less common call.
if (IsDependent)
TypeResult = Actions.ActOnDependentTag(CurScope, TagType, TUK,
- SS, Name, StartLoc, NameLoc);
+ SS, Name, StartLoc, NameLoc);
}
// If there is a body, parse it and inform the actions module.
@@ -927,11 +927,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// FIXME: The DeclSpec should keep the locations of both the keyword and the
// name (if there is one).
SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
-
+
if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID,
Result, Owned))
Diag(StartLoc, DiagID) << PrevSpec;
-
+
// At this point, we've successfully parsed a class-specifier in 'definition'
// form (e.g. "struct foo { int x; }". While we could just return here, we're
// going to look at what comes after it to improve error recovery. If an
@@ -984,14 +984,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (!isKnownToBeTypeSpecifier(NextToken()))
ExpectedSemi = false;
break;
-
- case tok::r_brace: // struct bar { struct foo {...} }
+
+ case tok::r_brace: // struct bar { struct foo {...} }
// Missing ';' at end of struct is accepted as an extension in C mode.
if (!getLang().CPlusPlus)
ExpectedSemi = false;
break;
}
-
+
if (ExpectedSemi) {
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
TagType == DeclSpec::TST_class ? "class"
@@ -1000,7 +1000,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// to ';' so that the rest of the code recovers as though there were an
// ';' after the definition.
PP.EnterToken(Tok);
- Tok.setKind(tok::semi);
+ Tok.setKind(tok::semi);
}
}
}
@@ -1084,7 +1084,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
// Parse optional '::' and optional nested-name-specifier.
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0,
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0,
/*EnteringContext=*/false);
// The location of the base class itself.
@@ -1251,7 +1251,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
// is a bitfield.
ColonProtectionRAIIObject X(*this);
-
+
CXX0XAttributeList AttrList;
// Optional C++0x attribute-specifier
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
@@ -1259,7 +1259,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::kw_using)) {
// FIXME: Check for template aliases
-
+
if (AttrList.HasAttr)
Diag(AttrList.Range.getBegin(), diag::err_attributes_not_allowed)
<< AttrList.Range;
@@ -1628,14 +1628,14 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
llvm::SmallVector<MemInitTy*, 4> MemInitializers;
bool AnyErrors = false;
-
+
do {
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
if (!MemInit.isInvalid())
MemInitializers.push_back(MemInit.get());
else
AnyErrors = true;
-
+
if (Tok.is(tok::comma))
ConsumeToken();
else if (Tok.is(tok::l_brace))
@@ -1869,7 +1869,7 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) {
ConsumeBracket();
ConsumeBracket();
-
+
if (Tok.is(tok::comma)) {
Diag(Tok.getLocation(), diag::err_expected_ident);
ConsumeToken();
@@ -1884,7 +1884,7 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) {
IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo();
SourceLocation ScopeLoc, AttrLoc = ConsumeToken();
-
+
// scoped attribute
if (Tok.is(tok::coloncolon)) {
ConsumeToken();
@@ -1894,7 +1894,7 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) {
SkipUntil(tok::r_square, tok::comma, true, true);
continue;
}
-
+
ScopeName = AttrName;
ScopeLoc = AttrLoc;
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 7ab0e71dc235..7b2b6e855bb7 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -375,6 +375,10 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
AtEnd.setBegin(AtLoc);
AtEnd.setEnd(Tok.getLocation());
break;
+ } else if (DirectiveKind == tok::objc_not_keyword) {
+ Diag(Tok, diag::err_objc_unknown_at);
+ SkipUntil(tok::semi);
+ continue;
}
// Eat the identifier.
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
index 342b0e6ef5e5..7b78070a27f8 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -43,8 +43,13 @@ void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E,
// Include the whole end token in the range.
EOffset += Lexer::MeasureTokenLength(E, R.getSourceMgr(), R.getLangOpts());
+ bool Invalid = false;
+ const char *BufferStart = SM.getBufferData(FID, &Invalid).data();
+ if (Invalid)
+ return;
+
HighlightRange(R.getEditBuffer(FID), BOffset, EOffset,
- SM.getBufferData(FID).first, StartTag, EndTag);
+ BufferStart, StartTag, EndTag);
}
/// HighlightRange - This is the same as the above method, but takes
diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile
index a6d3f7725689..04c353090dc7 100644
--- a/lib/Rewrite/Makefile
+++ b/lib/Rewrite/Makefile
@@ -15,7 +15,7 @@ LEVEL = ../../../..
LIBRARYNAME := clangRewrite
BUILD_ARCHIVE = 1
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index 9744496ac4fe..bf8ba701a842 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -165,8 +165,8 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
return I->second;
I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer()));
- std::pair<const char*, const char*> MB = SourceMgr->getBufferData(FID);
- I->second.Initialize(MB.first, MB.second);
+ llvm::StringRef MB = SourceMgr->getBufferData(FID);
+ I->second.Initialize(MB.begin(), MB.end());
return I->second;
}
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 5be6712c8397..237803a1c453 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -22,6 +22,7 @@ add_clang_library(clangSema
SemaExprObjC.cpp
SemaInit.cpp
SemaLookup.cpp
+ SemaObjCProperty.cpp
SemaOverload.cpp
SemaStmt.cpp
SemaTemplate.cpp
diff --git a/lib/Sema/Makefile b/lib/Sema/Makefile
index 158f1af213d4..3a5a99ad576a 100644
--- a/lib/Sema/Makefile
+++ b/lib/Sema/Makefile
@@ -16,7 +16,7 @@ LEVEL = ../../../..
LIBRARYNAME := clangSema
BUILD_ARCHIVE = 1
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index a94d07a6acc8..4c258448daf2 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -300,60 +300,38 @@ public:
/// \brief The set of static functions seen so far that have not been used.
std::vector<FunctionDecl*> UnusedStaticFuncs;
- /// An enum describing the kind of diagnostics to use when checking
- /// access.
- enum AccessDiagnosticsKind {
- /// Suppress diagnostics.
- ADK_quiet,
-
- /// Use the normal diagnostics.
- ADK_normal,
-
- /// Use the diagnostics appropriate for checking a covariant
- /// return type.
- ADK_covariance
- };
-
class AccessedEntity {
public:
- enum Kind {
- /// A member declaration found through lookup. The target is the
- /// member.
- Member,
-
- /// A base-to-derived conversion. The target is the base class.
- BaseToDerivedConversion,
-
- /// A derived-to-base conversion. The target is the base class.
- DerivedToBaseConversion
- };
-
- bool isMemberAccess() const { return K == Member; }
-
- static AccessedEntity makeMember(CXXRecordDecl *NamingClass,
- AccessSpecifier Access,
- NamedDecl *Target) {
- AccessedEntity E;
- E.K = Member;
- E.Access = Access;
- E.Target = Target;
- E.NamingClass = NamingClass;
- return E;
+ /// A member declaration found through lookup. The target is the
+ /// member.
+ enum MemberNonce { Member };
+
+ /// A hierarchy (base-to-derived or derived-to-base) conversion.
+ /// The target is the base class.
+ enum BaseNonce { Base };
+
+ bool isMemberAccess() const { return IsMember; }
+
+ AccessedEntity(MemberNonce _,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ NamedDecl *Target)
+ : Access(Access), IsMember(true),
+ Target(Target), NamingClass(NamingClass),
+ Diag(0) {
}
- static AccessedEntity makeBaseClass(bool BaseToDerived,
- CXXRecordDecl *BaseClass,
- CXXRecordDecl *DerivedClass,
- AccessSpecifier Access) {
- AccessedEntity E;
- E.K = BaseToDerived ? BaseToDerivedConversion : DerivedToBaseConversion;
- E.Access = Access;
- E.Target = BaseClass;
- E.NamingClass = DerivedClass;
- return E;
+ AccessedEntity(BaseNonce _,
+ CXXRecordDecl *BaseClass,
+ CXXRecordDecl *DerivedClass,
+ AccessSpecifier Access)
+ : Access(Access), IsMember(false),
+ Target(BaseClass), NamingClass(DerivedClass),
+ Diag(0) {
}
- Kind getKind() const { return Kind(K); }
+ bool isQuiet() const { return Diag.getDiagID() == 0; }
+
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
// These apply to member decls...
@@ -364,11 +342,32 @@ public:
CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
CXXRecordDecl *getDerivedClass() const { return NamingClass; }
+ /// Sets a diagnostic to be performed. The diagnostic is given
+ /// four (additional) arguments:
+ /// %0 - 0 if the entity was private, 1 if protected
+ /// %1 - the DeclarationName of the entity
+ /// %2 - the TypeDecl type of the naming class
+ /// %3 - the TypeDecl type of the declaring class
+ void setDiag(const PartialDiagnostic &PDiag) {
+ assert(isQuiet() && "partial diagnostic already defined");
+ Diag = PDiag;
+ }
+ PartialDiagnostic &setDiag(unsigned DiagID) {
+ assert(isQuiet() && "partial diagnostic already defined");
+ assert(DiagID && "creating null diagnostic");
+ Diag = PartialDiagnostic(DiagID);
+ return Diag;
+ }
+ const PartialDiagnostic &getDiag() const {
+ return Diag;
+ }
+
private:
- unsigned K : 2;
unsigned Access : 2;
+ bool IsMember;
NamedDecl *Target;
CXXRecordDecl *NamingClass;
+ PartialDiagnostic Diag;
};
struct DelayedDiagnostic {
@@ -384,9 +383,16 @@ public:
struct { NamedDecl *Decl; } DeprecationData;
/// Access control.
- AccessedEntity AccessData;
+ char AccessData[sizeof(AccessedEntity)];
};
+ void destroy() {
+ switch (Kind) {
+ case Access: getAccessData().~AccessedEntity(); break;
+ case Deprecation: break;
+ }
+ }
+
static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
NamedDecl *D) {
DelayedDiagnostic DD;
@@ -403,10 +409,16 @@ public:
DD.Kind = Access;
DD.Triggered = false;
DD.Loc = Loc;
- DD.AccessData = Entity;
+ new (&DD.getAccessData()) AccessedEntity(Entity);
return DD;
}
+ AccessedEntity &getAccessData() {
+ return *reinterpret_cast<AccessedEntity*>(AccessData);
+ }
+ const AccessedEntity &getAccessData() const {
+ return *reinterpret_cast<const AccessedEntity*>(AccessData);
+ }
};
/// \brief The stack of diagnostics that were delayed due to being
@@ -1469,7 +1481,7 @@ public:
void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const llvm::DenseSet<Selector>& InsMap);
-
+
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those it its super class.
void CollectImmediateProperties(ObjCContainerDecl *CDecl,
@@ -1482,7 +1494,35 @@ public:
ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
IdentifierInfo *NameII);
-
+
+ /// Called by ActOnProperty to handle @property declarations in
+ //// class extensions.
+ DeclPtrTy HandlePropertyInClassExtension(Scope *S,
+ ObjCCategoryDecl *CDecl,
+ SourceLocation AtLoc,
+ FieldDeclarator &FD,
+ Selector GetterSel,
+ Selector SetterSel,
+ const bool isAssign,
+ const bool isReadWrite,
+ const unsigned Attributes,
+ bool *isOverridingProperty,
+ QualType T,
+ tok::ObjCKeywordKind MethodImplKind);
+
+ /// Called by ActOnProperty and HandlePropertyInClassExtension to
+ /// handle creating the ObjcPropertyDecl for a category or @interface.
+ ObjCPropertyDecl *CreatePropertyDecl(Scope *S,
+ ObjCContainerDecl *CDecl,
+ SourceLocation AtLoc,
+ FieldDeclarator &FD,
+ Selector GetterSel,
+ Selector SetterSel,
+ const bool isAssign,
+ const bool isReadWrite,
+ const unsigned Attributes, QualType T,
+ tok::ObjCKeywordKind MethodImplKind);
+
/// AtomicPropertySetterGetterRules - This routine enforces the rule (via
/// warning) when atomic property has one but not the other user-declared
/// setter or getter.
@@ -2538,7 +2578,7 @@ public:
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess = false);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- AccessDiagnosticsKind ADK,
+ unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name);
@@ -2586,18 +2626,22 @@ public:
CXXConstructorDecl *D,
AccessSpecifier Access);
AccessResult CheckDestructorAccess(SourceLocation Loc,
- const RecordType *Record);
+ CXXDestructorDecl *Dtor,
+ const PartialDiagnostic &PDiag);
+ AccessResult CheckDirectMemberAccess(SourceLocation Loc,
+ NamedDecl *D,
+ const PartialDiagnostic &PDiag);
AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
Expr *ObjectExpr,
+ Expr *ArgExpr,
NamedDecl *D,
AccessSpecifier Access);
AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
- bool IsBaseToDerived,
QualType Base, QualType Derived,
const CXXBasePath &Path,
+ unsigned DiagID,
bool ForceCheck = false,
- bool ForceUnprivileged = false,
- AccessDiagnosticsKind ADK = ADK_normal);
+ bool ForceUnprivileged = false);
void CheckLookupAccess(const LookupResult &R);
@@ -3593,6 +3637,8 @@ public:
DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
const MultiLevelTemplateArgumentList &TemplateArgs);
+ bool CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl *> &Params);
+
// Objective-C declarations.
virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
@@ -4243,8 +4289,7 @@ private:
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
- const PartialDiagnostic &PD,
- bool Equality = false);
+ const BinaryOperator::Opcode* BinOpc = 0);
void CheckImplicitConversion(Expr *E, QualType Target);
};
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index eca8bb4c2a9b..f0a38d5970cc 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/ExprCXX.h"
using namespace clang;
@@ -55,7 +56,7 @@ struct EffectiveContext {
explicit EffectiveContext(DeclContext *DC) {
if (isa<FunctionDecl>(DC)) {
- Function = cast<FunctionDecl>(DC);
+ Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
DC = Function->getDeclContext();
} else
Function = 0;
@@ -85,10 +86,34 @@ static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
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))
return Sema::AR_accessible;
- // FIXME: implement
+ // 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());
+
+ // The decl pointers in EC have been canonicalized, so pointer
+ // equality is sufficient.
+ if (D == EC.Function || D == EC.Record)
+ return Sema::AR_accessible;
+ }
+
+ // FIXME: templates! templated contexts! dependent delay!
+ }
+
+ // That's it, give up.
return Sema::AR_inaccessible;
}
@@ -230,18 +255,11 @@ static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
NamedDecl *D = Entity.getTargetDecl();
CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
- if (isa<CXXConstructorDecl>(D)) {
- unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected
- : diag::err_access_ctor_private);
- S.Diag(Loc, DiagID)
- << S.Context.getTypeDeclType(DeclaringClass);
- } else {
- unsigned DiagID = (Access == AS_protected ? diag::err_access_protected
- : diag::err_access_private);
- S.Diag(Loc, DiagID)
- << D->getDeclName()
- << S.Context.getTypeDeclType(DeclaringClass);
- }
+ S.Diag(Loc, Entity.getDiag())
+ << (Access == AS_protected)
+ << D->getDeclName()
+ << S.Context.getTypeDeclType(NamingClass)
+ << S.Context.getTypeDeclType(DeclaringClass);
DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
}
@@ -249,39 +267,25 @@ static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
const EffectiveContext &EC,
AccessSpecifier Access,
- const Sema::AccessedEntity &Entity,
- Sema::AccessDiagnosticsKind ADK) {
- if (ADK == Sema::ADK_covariance) {
- S.Diag(Loc, diag::err_covariant_return_inaccessible_base)
- << S.Context.getTypeDeclType(Entity.getDerivedClass())
- << S.Context.getTypeDeclType(Entity.getBaseClass())
- << (Access == AS_protected);
- } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) {
- S.Diag(Loc, diag::err_downcast_from_inaccessible_base)
- << S.Context.getTypeDeclType(Entity.getDerivedClass())
- << S.Context.getTypeDeclType(Entity.getBaseClass())
- << (Access == AS_protected);
- } else {
- S.Diag(Loc, diag::err_upcast_to_inaccessible_base)
- << S.Context.getTypeDeclType(Entity.getDerivedClass())
- << S.Context.getTypeDeclType(Entity.getBaseClass())
- << (Access == AS_protected);
- }
+ const Sema::AccessedEntity &Entity) {
+ S.Diag(Loc, Entity.getDiag())
+ << (Access == AS_protected)
+ << DeclarationName()
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass());
DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
Entity.getBaseClass(), 0, Access);
}
-static void DiagnoseBadAccess(Sema &S,
- SourceLocation Loc,
+static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
const EffectiveContext &EC,
CXXRecordDecl *NamingClass,
AccessSpecifier Access,
- const Sema::AccessedEntity &Entity,
- Sema::AccessDiagnosticsKind ADK) {
+ const Sema::AccessedEntity &Entity) {
if (Entity.isMemberAccess())
DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
else
- DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK);
+ DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
}
@@ -344,8 +348,7 @@ static void TryElevateAccess(Sema &S,
static Sema::AccessResult CheckEffectiveAccess(Sema &S,
const EffectiveContext &EC,
SourceLocation Loc,
- Sema::AccessedEntity const &Entity,
- Sema::AccessDiagnosticsKind ADK) {
+ Sema::AccessedEntity const &Entity) {
AccessSpecifier Access = Entity.getAccess();
assert(Access != AS_public);
@@ -353,14 +356,14 @@ static Sema::AccessResult CheckEffectiveAccess(Sema &S,
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);
+ NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
if (!EC.Record) {
TryElevateAccess(S, EC, Entity, Access);
if (Access == AS_public) return Sema::AR_accessible;
- if (ADK != Sema::ADK_quiet)
- DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ if (!Entity.isQuiet())
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
return Sema::AR_inaccessible;
}
@@ -393,15 +396,13 @@ static Sema::AccessResult CheckEffectiveAccess(Sema &S,
}
// Okay, that's it, reject it.
- if (ADK != Sema::ADK_quiet)
- DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ if (!Entity.isQuiet())
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
return Sema::AR_inaccessible;
}
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
- const Sema::AccessedEntity &Entity,
- Sema::AccessDiagnosticsKind ADK
- = Sema::ADK_normal) {
+ const Sema::AccessedEntity &Entity) {
// If the access path is public, it's accessible everywhere.
if (Entity.getAccess() == AS_public)
return Sema::AR_accessible;
@@ -411,14 +412,13 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
// can actually change our effective context for the purposes of
// access control.
if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
- assert(ADK == Sema::ADK_normal && "delaying abnormal access check");
S.DelayedDiagnostics.push_back(
Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
return Sema::AR_delayed;
}
return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
- Loc, Entity, ADK);
+ Loc, Entity);
}
void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
@@ -426,18 +426,23 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
// declaration.
EffectiveContext EC(Ctx->getDeclContext());
- if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
+ if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
DD.Triggered = true;
}
Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
NamedDecl *D,
AccessSpecifier Access) {
- if (!getLangOptions().AccessControl || !E->getNamingClass())
+ if (!getLangOptions().AccessControl ||
+ !E->getNamingClass() ||
+ Access == AS_public)
return AR_accessible;
- return CheckAccess(*this, E->getNameLoc(),
- AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+ AccessedEntity Entity(AccessedEntity::Member,
+ E->getNamingClass(), Access, D);
+ Entity.setDiag(diag::err_access) << E->getSourceRange();
+
+ return CheckAccess(*this, E->getNameLoc(), Entity);
}
/// Perform access-control checking on a previously-unresolved member
@@ -445,56 +450,90 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
NamedDecl *D,
AccessSpecifier Access) {
- if (!getLangOptions().AccessControl)
+ if (!getLangOptions().AccessControl ||
+ Access == AS_public)
return AR_accessible;
- return CheckAccess(*this, E->getMemberLoc(),
- AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+ AccessedEntity Entity(AccessedEntity::Member,
+ E->getNamingClass(), Access, D);
+ Entity.setDiag(diag::err_access) << E->getSourceRange();
+
+ return CheckAccess(*this, E->getMemberLoc(), Entity);
}
Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
- const RecordType *RT) {
+ CXXDestructorDecl *Dtor,
+ const PartialDiagnostic &PDiag) {
if (!getLangOptions().AccessControl)
return AR_accessible;
- CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
- CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
-
+ // There's never a path involved when checking implicit destructor access.
AccessSpecifier Access = Dtor->getAccess();
if (Access == AS_public)
return AR_accessible;
- return CheckAccess(*this, Loc,
- AccessedEntity::makeMember(NamingClass, Access, Dtor));
+ CXXRecordDecl *NamingClass = Dtor->getParent();
+ AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor);
+ Entity.setDiag(PDiag); // TODO: avoid copy
+
+ return CheckAccess(*this, Loc, Entity);
}
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
AccessSpecifier Access) {
- if (!getLangOptions().AccessControl)
+ if (!getLangOptions().AccessControl ||
+ Access == AS_public)
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
- return CheckAccess(*this, UseLoc,
- AccessedEntity::makeMember(NamingClass, Access, Constructor));
+ AccessedEntity Entity(AccessedEntity::Member,
+ NamingClass, Access, Constructor);
+ Entity.setDiag(diag::err_access_ctor);
+
+ return CheckAccess(*this, UseLoc, Entity);
+}
+
+/// Checks direct (i.e. non-inherited) access to an arbitrary class
+/// member.
+Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
+ NamedDecl *Target,
+ const PartialDiagnostic &Diag) {
+ AccessSpecifier Access = Target->getAccess();
+ if (!getLangOptions().AccessControl ||
+ Access == AS_public)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
+ AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target);
+ Entity.setDiag(Diag);
+ return CheckAccess(*this, UseLoc, 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) {
- if (!getLangOptions().AccessControl)
+ if (!getLangOptions().AccessControl ||
+ Access == 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());
- return CheckAccess(*this, OpLoc,
- AccessedEntity::makeMember(NamingClass, Access, MemberOperator));
+ AccessedEntity Entity(AccessedEntity::Member,
+ NamingClass, Access, MemberOperator);
+ Entity.setDiag(diag::err_access)
+ << ObjectExpr->getSourceRange()
+ << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
+
+ return CheckAccess(*this, OpLoc, Entity);
}
/// Checks access for a hierarchy conversion.
@@ -507,31 +546,29 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
/// context had no special privileges
/// \param ADK controls the kind of diagnostics that are used
Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
- bool IsBaseToDerived,
QualType Base,
QualType Derived,
const CXXBasePath &Path,
+ unsigned DiagID,
bool ForceCheck,
- bool ForceUnprivileged,
- AccessDiagnosticsKind ADK) {
+ bool ForceUnprivileged) {
if (!ForceCheck && !getLangOptions().AccessControl)
return AR_accessible;
if (Path.Access == AS_public)
return AR_accessible;
- // TODO: preserve the information about which types exactly were used.
CXXRecordDecl *BaseD, *DerivedD;
BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
- AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived,
- BaseD, DerivedD,
- Path.Access);
+
+ AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
+ if (DiagID)
+ Entity.setDiag(DiagID) << Derived << Base;
if (ForceUnprivileged)
- return CheckEffectiveAccess(*this, EffectiveContext(),
- AccessLoc, Entity, ADK);
- return CheckAccess(*this, AccessLoc, Entity, ADK);
+ return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
+ return CheckAccess(*this, AccessLoc, Entity);
}
/// Checks access to all the declarations in the given result set.
@@ -540,9 +577,13 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
&& "performing access check without access control");
assert(R.getNamingClass() && "performing access check without naming class");
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- if (I.getAccess() != AS_public)
- CheckAccess(*this, R.getNameLoc(),
- AccessedEntity::makeMember(R.getNamingClass(),
- I.getAccess(), *I));
+ 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);
+ Entity.setDiag(diag::err_access);
+
+ CheckAccess(*this, R.getNameLoc(), Entity);
+ }
+ }
}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index e04abd2aac97..014cec2b650c 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -780,9 +780,9 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
}
if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
- /*IsBaseToDerived*/ true,
SrcType, DestType,
- Paths.front())) {
+ Paths.front(),
+ diag::err_downcast_from_inaccessible_base)) {
msg = 0;
return TC_Failed;
}
@@ -858,9 +858,9 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
}
if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
- /*IsBaseToDerived*/ false,
DestType, SrcType,
- Paths.front())) {
+ Paths.front(),
+ diag::err_upcast_to_inaccessible_base)) {
msg = 0;
return TC_Failed;
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 30a6ab465538..3fac79deba4b 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -59,9 +59,12 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
// Re-lex the token to get its length and original spelling.
std::pair<FileID, unsigned> LocInfo =
SourceMgr.getDecomposedLoc(StrTokSpellingLoc);
- std::pair<const char *,const char *> Buffer =
- SourceMgr.getBufferData(LocInfo.first);
- const char *StrData = Buffer.first+LocInfo.second;
+ bool Invalid = false;
+ llvm::StringRef Buffer = SourceMgr.getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return StrTokSpellingLoc;
+
+ const char *StrData = Buffer.data()+LocInfo.second;
// Create a langops struct and enable trigraphs. This is sufficient for
// relexing tokens.
@@ -69,8 +72,8 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
LangOpts.Trigraphs = true;
// Create a lexer starting at the beginning of this token.
- Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.first, StrData,
- Buffer.second);
+ Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.begin(), StrData,
+ Buffer.end());
Token TheTok;
TheLexer.LexFromRawLexer(TheTok);
@@ -2011,10 +2014,9 @@ bool IsSameFloatAfterCast(const APValue &value,
/// \param lex the left-hand expression
/// \param rex the right-hand expression
/// \param OpLoc the location of the joining operator
-/// \param Equality whether this is an "equality-like" join, which
-/// suppresses the warning in some cases
+/// \param BinOpc binary opcode or 0
void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
- const PartialDiagnostic &PD, bool Equality) {
+ const BinaryOperator::Opcode* BinOpc) {
// Don't warn if we're in an unevaluated context.
if (ExprEvalContexts.back().Context == Unevaluated)
return;
@@ -2075,17 +2077,51 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
// If the signed operand is non-negative, then the signed->unsigned
// conversion won't change it.
- if (signedRange.NonNegative)
+ if (signedRange.NonNegative) {
+ // Emit warnings for comparisons of unsigned to integer constant 0.
+ // always false: x < 0 (or 0 > x)
+ // always true: x >= 0 (or 0 <= x)
+ llvm::APSInt X;
+ if (BinOpc && signedOperand->isIntegerConstantExpr(X, Context) && X == 0) {
+ if (signedOperand != lex) {
+ if (*BinOpc == BinaryOperator::LT) {
+ Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
+ << "< 0" << "false"
+ << lex->getSourceRange() << rex->getSourceRange();
+ }
+ else if (*BinOpc == BinaryOperator::GE) {
+ Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
+ << ">= 0" << "true"
+ << lex->getSourceRange() << rex->getSourceRange();
+ }
+ }
+ else {
+ if (*BinOpc == BinaryOperator::GT) {
+ Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
+ << "0 >" << "false"
+ << lex->getSourceRange() << rex->getSourceRange();
+ }
+ else if (*BinOpc == BinaryOperator::LE) {
+ Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
+ << "0 <=" << "true"
+ << lex->getSourceRange() << rex->getSourceRange();
+ }
+ }
+ }
return;
+ }
// For (in)equality comparisons, if the unsigned operand is a
// constant which cannot collide with a overflowed signed operand,
// then reinterpreting the signed operand as unsigned will not
// change the result of the comparison.
- if (Equality && unsignedRange.Width < unsignedWidth)
+ if (BinOpc &&
+ (*BinOpc == BinaryOperator::EQ || *BinOpc == BinaryOperator::NE) &&
+ unsignedRange.Width < unsignedWidth)
return;
- Diag(OpLoc, PD)
+ Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison
+ : diag::warn_mixed_sign_conditional)
<< lt << rt << lex->getSourceRange() << rex->getSourceRange();
}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index edf1bc51eb92..4693fa974edb 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -365,8 +365,7 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
// Friend declarations and declarations introduced due to friends are never
// added as results.
- if (isa<FriendDecl>(ND) ||
- (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
+ if (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend))
return false;
// Class template (partial) specializations are never added as results.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 94fcfc6c29e6..dab7d883a1d6 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2262,6 +2262,13 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
return true;
}
+static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) {
+ CXXScopeSpec &SS = D.getCXXScopeSpec();
+ if (!SS.isSet()) return;
+ DD->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
+ SS.getRange());
+}
+
NamedDecl*
Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
@@ -2371,6 +2378,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.isInvalidType())
NewVD->setInvalidDecl();
+ SetNestedNameSpecifier(NewVD, D);
+
if (D.getDeclSpec().isThreadSpecified()) {
if (NewVD->hasLocalStorage())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global);
@@ -2718,6 +2727,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
D.getIdentifierLoc(), Name, R,
isInline,
/*isImplicitlyDeclared=*/false);
+ NewFD->setTypeSourceInfo(TInfo);
isVirtualOkay = true;
} else {
@@ -2798,6 +2808,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.isInvalidType())
NewFD->setInvalidDecl();
+ SetNestedNameSpecifier(NewFD, D);
+
// Set the lexical context. If the declarator has a C++
// scope specifier, or is the object of a friend declaration, the
// lexical context will be different from the semantic context.
@@ -4248,9 +4260,10 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
CompoundStmt *Compound = isa<CXXTryStmt>(Body) ?
cast<CXXTryStmt>(Body)->getTryBlock() :
cast<CompoundStmt>(Body);
- std::vector<Stmt*> Elements(Compound->body_begin(), Compound->body_end());
+ llvm::SmallVector<Stmt*, 64> Elements(Compound->body_begin(),
+ Compound->body_end());
Elements.push_back(L);
- Compound->setStmts(Context, &Elements[0], Elements.size());
+ Compound->setStmts(Context, Elements.data(), Elements.size());
}
if (Body) {
@@ -4845,6 +4858,13 @@ CreateNewDecl:
cast_or_null<RecordDecl>(PrevDecl));
}
+ // Maybe add qualifier info.
+ if (SS.isNotEmpty()) {
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ New->setQualifierInfo(NNS, SS.getRange());
+ }
+
if (Kind != TagDecl::TK_enum) {
// Handle #pragma pack: if the #pragma pack stack has non-default
// alignment, make up a packed attribute for this decl. These
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 242d66fa521f..73a34f8107e0 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1945,11 +1945,19 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
FD->getLocation(), DeclarationName(II),
FD->getType(), FD->getTypeSourceInfo());
+ if (FD->getQualifier()) {
+ FunctionDecl *NewFD = cast<FunctionDecl>(NewD);
+ NewFD->setQualifierInfo(FD->getQualifier(), FD->getQualifierRange());
+ }
} else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
VD->getLocation(), II,
VD->getType(), VD->getTypeSourceInfo(),
VD->getStorageClass());
+ if (VD->getQualifier()) {
+ VarDecl *NewVD = cast<VarDecl>(NewD);
+ NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange());
+ }
}
return NewD;
}
@@ -2030,6 +2038,8 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) {
assert(SavedIndex <= DelayedDiagnostics.size() &&
"saved index is out of bounds");
+ unsigned E = DelayedDiagnostics.size();
+
// We only want to actually emit delayed diagnostics when we
// successfully parsed a decl.
Decl *D = Ctx ? Ctx.getAs<Decl>() : 0;
@@ -2040,7 +2050,7 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) {
// only the declarator pops will be passed decls. This is correct;
// we really do need to consider delayed diagnostics from the decl spec
// for each of the different declarations.
- for (unsigned I = 0, E = DelayedDiagnostics.size(); I != E; ++I) {
+ for (unsigned I = 0; I != E; ++I) {
if (DelayedDiagnostics[I].Triggered)
continue;
@@ -2056,6 +2066,10 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) {
}
}
+ // Destroy all the delayed diagnostics we're about to pop off.
+ for (unsigned I = SavedIndex; I != E; ++I)
+ DelayedDiagnostics[I].destroy();
+
DelayedDiagnostics.set_size(SavedIndex);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e694cb470c25..c27b0d5013c6 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -298,6 +298,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
Invalid = true;
} else if (OldParam->hasDefaultArg()) {
// Merge the old default argument into the new parameter
+ NewParam->setHasInheritedDefaultArg();
if (OldParam->hasUninstantiatedDefaultArg())
NewParam->setUninstantiatedDefaultArg(
OldParam->getUninstantiatedDefaultArg());
@@ -719,7 +720,7 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
/// if there is an error.
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- AccessDiagnosticsKind ADK,
+ unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name) {
@@ -735,15 +736,12 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (ADK == ADK_quiet)
+ if (!InaccessibleBaseID)
return false;
// Check that the base class can be accessed.
- switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false,
- Base, Derived, Paths.front(),
- /*force*/ false,
- /*unprivileged*/ false,
- ADK)) {
+ switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
+ InaccessibleBaseID)) {
case AR_accessible: return false;
case AR_inaccessible: return true;
case AR_dependent: return false;
@@ -779,7 +777,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess) {
return CheckDerivedToBaseConversion(Derived, Base,
- IgnoreAccess ? ADK_quiet : ADK_normal,
+ IgnoreAccess ? 0
+ : diag::err_upcast_to_inaccessible_base,
diag::err_ambiguous_derived_to_base_conv,
Loc, Range, DeclarationName());
}
@@ -1657,6 +1656,11 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
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);
@@ -1848,6 +1852,11 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
// Ignore dependent destructors.
if (Destructor->isDependentContext())
return;
+
+ // FIXME: all the access-control diagnostics are positioned on the
+ // field/base declaration. That's probably good; that said, the
+ // user might reasonably want to know why the destructor is being
+ // emitted, and we currently don't say.
CXXRecordDecl *ClassDecl = Destructor->getParent();
@@ -1866,25 +1875,41 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
if (FieldClassDecl->hasTrivialDestructor())
continue;
- const CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
+ CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
+ CheckDestructorAccess(Field->getLocation(), Dtor,
+ PartialDiagnostic(diag::err_access_dtor_field)
+ << Field->getDeclName()
+ << FieldType);
+
MarkDeclarationReferenced(Destructor->getLocation(),
const_cast<CXXDestructorDecl*>(Dtor));
}
+ llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
+
// Bases.
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
- // Ignore virtual bases.
+ // Bases are always records in a well-formed non-dependent class.
+ const RecordType *RT = Base->getType()->getAs<RecordType>();
+
+ // Remember direct virtual bases.
if (Base->isVirtual())
- continue;
+ DirectVirtualBases.insert(RT);
// Ignore trivial destructors.
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (BaseClassDecl->hasTrivialDestructor())
continue;
+
+ CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+
+ // FIXME: caret should be on the start of the class name
+ CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor,
+ PartialDiagnostic(diag::err_access_dtor_base)
+ << Base->getType()
+ << Base->getSourceRange());
- const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
MarkDeclarationReferenced(Destructor->getLocation(),
const_cast<CXXDestructorDecl*>(Dtor));
}
@@ -1892,13 +1917,24 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
// Virtual bases.
for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+
+ // Bases are always records in a well-formed non-dependent class.
+ const RecordType *RT = VBase->getType()->getAs<RecordType>();
+
+ // Ignore direct virtual bases.
+ if (DirectVirtualBases.count(RT))
+ continue;
+
// Ignore trivial destructors.
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (BaseClassDecl->hasTrivialDestructor())
continue;
-
- const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+
+ CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+ CheckDestructorAccess(ClassDecl->getLocation(), Dtor,
+ PartialDiagnostic(diag::err_access_dtor_vbase)
+ << VBase->getType());
+
MarkDeclarationReferenced(Destructor->getLocation(),
const_cast<CXXDestructorDecl*>(Dtor));
}
@@ -2392,22 +2428,26 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// If a class has no user-declared destructor, a destructor is
// declared implicitly. An implicitly-declared destructor is an
// inline public member of its class.
+ QualType Ty = Context.getFunctionType(Context.VoidTy,
+ 0, 0, false, 0,
+ /*FIXME:*/false,
+ false, 0, 0, false,
+ CC_Default);
+
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
CXXDestructorDecl *Destructor
= CXXDestructorDecl::Create(Context, ClassDecl,
- ClassDecl->getLocation(), Name,
- Context.getFunctionType(Context.VoidTy,
- 0, 0, false, 0,
- /*FIXME:*/false,
- false, 0, 0, false,
- CC_Default),
+ ClassDecl->getLocation(), Name, Ty,
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
ClassDecl->addDecl(Destructor);
+
+ // This could be uniqued if it ever proves significant.
+ Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
AddOverriddenMethods(ClassDecl, Destructor);
}
@@ -3779,45 +3819,8 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
DeclContext *PreviousContext = CurContext;
CurContext = Destructor;
- // C++ [class.dtor] p5
- // Before the implicitly-declared default destructor for a class is
- // implicitly defined, all the implicitly-declared default destructors
- // for its base class and its non-static data members shall have been
- // implicitly defined.
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); Base != E; ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasTrivialDestructor()) {
- if (CXXDestructorDecl *BaseDtor =
- const_cast<CXXDestructorDecl*>(BaseClassDecl->getDestructor(Context)))
- MarkDeclarationReferenced(CurrentLocation, BaseDtor);
- else
- assert(false &&
- "DefineImplicitDestructor - missing dtor in a base class");
- }
- }
+ MarkBaseAndMemberDestructorsReferenced(Destructor);
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); Field != E; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (!FieldClassDecl->hasTrivialDestructor()) {
- if (CXXDestructorDecl *FieldDtor =
- const_cast<CXXDestructorDecl*>(
- FieldClassDecl->getDestructor(Context)))
- MarkDeclarationReferenced(CurrentLocation, FieldDtor);
- else
- assert(false &&
- "DefineImplicitDestructor - missing dtor in class of a data member");
- }
- }
- }
-
// FIXME: If CheckDestructor fails, we should emit a note about where the
// implicit destructor was needed.
if (CheckDestructor(Destructor)) {
@@ -3859,8 +3862,14 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *BaseAssignOpMethod =
getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- BaseClassDecl))
+ BaseClassDecl)) {
+ CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
+ BaseAssignOpMethod,
+ PartialDiagnostic(diag::err_access_assign_base)
+ << Base->getType());
+
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
+ }
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
E = ClassDecl->field_end(); Field != E; ++Field) {
@@ -3872,8 +3881,14 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (CXXMethodDecl *FieldAssignOpMethod =
getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- FieldClassDecl))
+ FieldClassDecl)) {
+ CheckDirectMemberAccess(Field->getLocation(),
+ FieldAssignOpMethod,
+ PartialDiagnostic(diag::err_access_assign_field)
+ << Field->getDeclName() << Field->getType());
+
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
+ }
} else if (FieldType->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
@@ -3948,8 +3963,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(Context, TypeQuals))
+ BaseClassDecl->getCopyConstructor(Context, TypeQuals)) {
+ CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
+ BaseCopyCtor,
+ PartialDiagnostic(diag::err_access_copy_base)
+ << Base->getType());
+
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
+ }
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
@@ -3961,8 +3982,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (CXXConstructorDecl *FieldCopyCtor =
- FieldClassDecl->getCopyConstructor(Context, TypeQuals))
+ FieldClassDecl->getCopyConstructor(Context, TypeQuals)) {
+ CheckDirectMemberAccess(Field->getLocation(),
+ FieldCopyCtor,
+ PartialDiagnostic(diag::err_access_copy_field)
+ << Field->getDeclName() << Field->getType());
+
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
+ }
}
}
CopyConstructor->setUsed();
@@ -4052,7 +4079,10 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
!ClassDecl->hasTrivialDestructor()) {
CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
MarkDeclarationReferenced(VD->getLocation(), Destructor);
- CheckDestructorAccess(VD->getLocation(), Record);
+ CheckDestructorAccess(VD->getLocation(), Destructor,
+ PartialDiagnostic(diag::err_access_dtor_var)
+ << VD->getDeclName()
+ << VD->getType());
}
}
@@ -5715,7 +5745,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
}
// Check if we the conversion from derived to base is valid.
- if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance,
+ if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
+ diag::err_covariant_return_inaccessible_base,
diag::err_covariant_return_ambiguous_derived_to_base_conv,
// FIXME: Should this point to the return type?
New->getLocation(), SourceRange(), New->getDeclName())) {
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 762ef38c9736..b2f671760ebe 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -20,25 +20,6 @@
#include "clang/Parse/DeclSpec.h"
using namespace clang;
-bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
- ObjCMethodDecl *GetterMethod,
- SourceLocation Loc) {
- if (GetterMethod &&
- GetterMethod->getResultType() != property->getType()) {
- AssignConvertType result = Incompatible;
- if (property->getType()->isObjCObjectPointerType())
- result = CheckAssignmentConstraints(GetterMethod->getResultType(), property->getType());
- if (result != Compatible) {
- Diag(Loc, diag::warn_accessor_property_type_mismatch)
- << property->getDeclName()
- << GetterMethod->getSelector();
- Diag(GetterMethod->getLocation(), diag::note_declared_at);
- return true;
- }
- }
- return false;
-}
-
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
/// and user declared, in the method definition's AST.
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
@@ -361,171 +342,6 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
}
}
-/// DiagnosePropertyMismatch - Compares two properties for their
-/// attributes and types and warns on a variety of inconsistencies.
-///
-void
-Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
- ObjCPropertyDecl *SuperProperty,
- const IdentifierInfo *inheritedName) {
- ObjCPropertyDecl::PropertyAttributeKind CAttr =
- Property->getPropertyAttributes();
- ObjCPropertyDecl::PropertyAttributeKind SAttr =
- SuperProperty->getPropertyAttributes();
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
- && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
- Diag(Property->getLocation(), diag::warn_readonly_property)
- << Property->getDeclName() << inheritedName;
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "copy" << inheritedName;
- else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "retain" << inheritedName;
-
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "atomic" << inheritedName;
- if (Property->getSetterName() != SuperProperty->getSetterName())
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "setter" << inheritedName;
- if (Property->getGetterName() != SuperProperty->getGetterName())
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "getter" << inheritedName;
-
- QualType LHSType =
- Context.getCanonicalType(SuperProperty->getType());
- QualType RHSType =
- Context.getCanonicalType(Property->getType());
-
- if (!Context.typesAreCompatible(LHSType, RHSType)) {
- // FIXME: Incorporate this test with typesAreCompatible.
- if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
- if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
- return;
- Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
- << Property->getType() << SuperProperty->getType() << inheritedName;
- }
-}
-
-/// ComparePropertiesInBaseAndSuper - This routine compares property
-/// declarations in base and its super class, if any, and issues
-/// diagnostics in a variety of inconsistant situations.
-///
-void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
- ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
- if (!SDecl)
- return;
- // FIXME: O(N^2)
- for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(),
- E = SDecl->prop_end(); S != E; ++S) {
- ObjCPropertyDecl *SuperPDecl = (*S);
- // Does property in super class has declaration in current class?
- for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(),
- E = IDecl->prop_end(); I != E; ++I) {
- ObjCPropertyDecl *PDecl = (*I);
- if (SuperPDecl->getIdentifier() == PDecl->getIdentifier())
- DiagnosePropertyMismatch(PDecl, SuperPDecl,
- SDecl->getIdentifier());
- }
- }
-}
-
-/// MatchOneProtocolPropertiesInClass - This routine goes thru the list
-/// of properties declared in a protocol and compares their attribute against
-/// the same property declared in the class or category.
-void
-Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
- ObjCProtocolDecl *PDecl) {
- ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
- if (!IDecl) {
- // Category
- ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
- assert (CatDecl && "MatchOneProtocolPropertiesInClass");
- if (!CatDecl->IsClassExtension())
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = (*P);
- ObjCCategoryDecl::prop_iterator CP, CE;
- // Is this property already in category's list of properties?
- for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP)
- if ((*CP)->getIdentifier() == Pr->getIdentifier())
- break;
- if (CP != CE)
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
- }
- return;
- }
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = (*P);
- ObjCInterfaceDecl::prop_iterator CP, CE;
- // Is this property already in class's list of properties?
- for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP)
- if ((*CP)->getIdentifier() == Pr->getIdentifier())
- break;
- if (CP != CE)
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
- }
-}
-
-/// CompareProperties - This routine compares properties
-/// declared in 'ClassOrProtocol' objects (which can be a class or an
-/// inherited protocol with the list of properties for class/category 'CDecl'
-///
-void Sema::CompareProperties(Decl *CDecl,
- DeclPtrTy ClassOrProtocol) {
- Decl *ClassDecl = ClassOrProtocol.getAs<Decl>();
- ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
-
- if (!IDecl) {
- // Category
- ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
- assert (CatDecl && "CompareProperties");
- if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
- for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(),
- E = MDecl->protocol_end(); P != E; ++P)
- // Match properties of category with those of protocol (*P)
- MatchOneProtocolPropertiesInClass(CatDecl, *P);
-
- // Go thru the list of protocols for this category and recursively match
- // their properties with those in the category.
- for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(),
- E = CatDecl->protocol_end(); P != E; ++P)
- CompareProperties(CatDecl, DeclPtrTy::make(*P));
- } else {
- ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
- for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
- E = MD->protocol_end(); P != E; ++P)
- MatchOneProtocolPropertiesInClass(CatDecl, *P);
- }
- return;
- }
-
- if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
- for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
- E = MDecl->protocol_end(); P != E; ++P)
- // Match properties of class IDecl with those of protocol (*P).
- MatchOneProtocolPropertiesInClass(IDecl, *P);
-
- // Go thru the list of protocols for this class and recursively match
- // their properties with those declared in the class.
- for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(),
- E = IDecl->protocol_end(); P != E; ++P)
- CompareProperties(IDecl, DeclPtrTy::make(*P));
- } else {
- ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
- for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
- E = MD->protocol_end(); P != E; ++P)
- MatchOneProtocolPropertiesInClass(IDecl, *P);
- }
-}
-
/// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of
/// a class method in its extension.
///
@@ -941,57 +757,6 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
}
}
-/// isPropertyReadonly - Return true if property is readonly, by searching
-/// for the property in the class and in its categories and implementations
-///
-bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
- ObjCInterfaceDecl *IDecl) {
- // by far the most common case.
- if (!PDecl->isReadOnly())
- return false;
- // Even if property is ready only, if interface has a user defined setter,
- // it is not considered read only.
- if (IDecl->getInstanceMethod(PDecl->getSetterName()))
- return false;
-
- // Main class has the property as 'readonly'. Must search
- // through the category list to see if the property's
- // attribute has been over-ridden to 'readwrite'.
- for (ObjCCategoryDecl *Category = IDecl->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
- // Even if property is ready only, if a category has a user defined setter,
- // it is not considered read only.
- if (Category->getInstanceMethod(PDecl->getSetterName()))
- return false;
- ObjCPropertyDecl *P =
- Category->FindPropertyDeclaration(PDecl->getIdentifier());
- if (P && !P->isReadOnly())
- return false;
- }
-
- // Also, check for definition of a setter method in the implementation if
- // all else failed.
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) {
- if (ObjCImplementationDecl *IMD =
- dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) {
- if (IMD->getInstanceMethod(PDecl->getSetterName()))
- return false;
- } else if (ObjCCategoryImplDecl *CIMD =
- dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
- if (CIMD->getInstanceMethod(PDecl->getSetterName()))
- return false;
- }
- }
- // Lastly, look through the implementation (if one is in scope).
- if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation())
- if (ImpDecl->getInstanceMethod(PDecl->getSetterName()))
- return false;
- // If all fails, look at the super class.
- if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass())
- return isPropertyReadonly(PDecl, SIDecl);
- return true;
-}
-
/// FIXME: Type hierarchies in Objective-C can be deep. We could most likely
/// improve the efficiency of selector lookups and type checking by associating
/// with each protocol / interface / category the flattened instance tables. If
@@ -1131,140 +896,6 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
}
}
-/// CollectImmediateProperties - This routine collects all properties in
-/// the class and its conforming protocols; but not those it its super class.
-void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
- if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
- E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- PropMap[Prop->getIdentifier()] = Prop;
- }
- // scan through class's protocols.
- for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
- E = IDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap);
- }
- if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- if (!CATDecl->IsClassExtension())
- for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
- E = CATDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- PropMap[Prop->getIdentifier()] = Prop;
- }
- // scan through class's protocols.
- for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
- E = CATDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap);
- }
- else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
- if (!PropEntry)
- PropEntry = Prop;
- }
- // scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap);
- }
-}
-
-/// LookupPropertyDecl - Looks up a property in the current class and all
-/// its protocols.
-ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
- IdentifierInfo *II) {
- if (const ObjCInterfaceDecl *IDecl =
- dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
- E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- if (Prop->getIdentifier() == II)
- return Prop;
- }
- // scan through class's protocols.
- for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
- E = IDecl->protocol_end(); PI != E; ++PI) {
- ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
- if (Prop)
- return Prop;
- }
- }
- else if (const ObjCProtocolDecl *PDecl =
- dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- if (Prop->getIdentifier() == II)
- return Prop;
- }
- // scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI) {
- ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
- if (Prop)
- return Prop;
- }
- }
- return 0;
-}
-
-
-void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
- ObjCContainerDecl *CDecl,
- const llvm::DenseSet<Selector>& InsMap) {
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
- CollectImmediateProperties(CDecl, PropMap);
- if (PropMap.empty())
- return;
-
- llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
- for (ObjCImplDecl::propimpl_iterator
- I = IMPDecl->propimpl_begin(),
- EI = IMPDecl->propimpl_end(); I != EI; ++I)
- PropImplMap.insert((*I)->getPropertyDecl());
-
- for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
- P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = P->second;
- // Is there a matching propery synthesize/dynamic?
- if (Prop->isInvalidDecl() ||
- Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
- PropImplMap.count(Prop))
- continue;
- if (LangOpts.ObjCNonFragileABI2) {
- ActOnPropertyImplDecl(IMPDecl->getLocation(),
- SourceLocation(),
- true, DeclPtrTy::make(IMPDecl),
- Prop->getIdentifier(),
- Prop->getIdentifier());
- continue;
- }
- if (!InsMap.count(Prop->getGetterName())) {
- Diag(Prop->getLocation(),
- isa<ObjCCategoryDecl>(CDecl) ?
- diag::warn_setter_getter_impl_required_in_category :
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getGetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
- }
-
- if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
- Diag(Prop->getLocation(),
- isa<ObjCCategoryDecl>(CDecl) ?
- diag::warn_setter_getter_impl_required_in_category :
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getSetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
- }
- }
-}
-
void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool IncompleteImpl) {
@@ -1336,41 +967,6 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
assert(false && "invalid ObjCContainerDecl type.");
}
-void
-Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
- ObjCContainerDecl* IDecl) {
- // Rules apply in non-GC mode only
- if (getLangOptions().getGCMode() != LangOptions::NonGC)
- return;
- for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(),
- E = IDecl->prop_end();
- I != E; ++I) {
- ObjCPropertyDecl *Property = (*I);
- unsigned Attributes = Property->getPropertyAttributes();
- // We only care about readwrite atomic property.
- if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) ||
- !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite))
- continue;
- if (const ObjCPropertyImplDecl *PIDecl
- = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) {
- if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
- continue;
- ObjCMethodDecl *GetterMethod =
- IMPDecl->getInstanceMethod(Property->getGetterName());
- ObjCMethodDecl *SetterMethod =
- IMPDecl->getInstanceMethod(Property->getSetterName());
- if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
- SourceLocation MethodLoc =
- (GetterMethod ? GetterMethod->getLocation()
- : SetterMethod->getLocation());
- Diag(MethodLoc, diag::warn_atomic_property_rule)
- << Property->getIdentifier();
- Diag(Property->getLocation(), diag::note_property_declare);
- }
- }
- }
-}
-
/// ActOnForwardClassDeclaration -
Action::DeclPtrTy
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
@@ -1638,111 +1234,6 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
return MethList.Method;
}
-/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
-/// have the property type and issue diagnostics if they don't.
-/// Also synthesize a getter/setter method if none exist (and update the
-/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized
-/// methods is the "right" thing to do.
-void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
- ObjCContainerDecl *CD) {
- ObjCMethodDecl *GetterMethod, *SetterMethod;
-
- GetterMethod = CD->getInstanceMethod(property->getGetterName());
- SetterMethod = CD->getInstanceMethod(property->getSetterName());
- DiagnosePropertyAccessorMismatch(property, GetterMethod,
- property->getLocation());
-
- if (SetterMethod) {
- ObjCPropertyDecl::PropertyAttributeKind CAttr =
- property->getPropertyAttributes();
- if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) &&
- Context.getCanonicalType(SetterMethod->getResultType()) !=
- Context.VoidTy)
- Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
- if (SetterMethod->param_size() != 1 ||
- ((*SetterMethod->param_begin())->getType() != property->getType())) {
- Diag(property->getLocation(),
- diag::warn_accessor_property_type_mismatch)
- << property->getDeclName()
- << SetterMethod->getSelector();
- Diag(SetterMethod->getLocation(), diag::note_declared_at);
- }
- }
-
- // Synthesize getter/setter methods if none exist.
- // Find the default getter and if one not found, add one.
- // FIXME: The synthesized property we set here is misleading. We almost always
- // synthesize these methods unless the user explicitly provided prototypes
- // (which is odd, but allowed). Sema should be typechecking that the
- // declarations jive in that situation (which it is not currently).
- if (!GetterMethod) {
- // No instance method of same name as property getter name was found.
- // Declare a getter method and add it to the list of methods
- // for this class.
- GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
- property->getLocation(), property->getGetterName(),
- property->getType(), 0, CD, true, false, true,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
- CD->addDecl(GetterMethod);
- } else
- // A user declared getter will be synthesize when @synthesize of
- // the property with the same name is seen in the @implementation
- GetterMethod->setSynthesized(true);
- property->setGetterMethodDecl(GetterMethod);
-
- // Skip setter if property is read-only.
- if (!property->isReadOnly()) {
- // Find the default setter and if one not found, add one.
- if (!SetterMethod) {
- // No instance method of same name as property setter name was found.
- // Declare a setter method and add it to the list of methods
- // for this class.
- SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
- property->getLocation(),
- property->getSetterName(),
- Context.VoidTy, 0, CD, true, false, true,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
- // Invent the arguments for the setter. We don't bother making a
- // nice name for the argument.
- ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
- property->getLocation(),
- property->getIdentifier(),
- property->getType(),
- /*TInfo=*/0,
- VarDecl::None,
- 0);
- SetterMethod->setMethodParams(Context, &Argument, 1);
- CD->addDecl(SetterMethod);
- } else
- // A user declared setter will be synthesize when @synthesize of
- // the property with the same name is seen in the @implementation
- SetterMethod->setSynthesized(true);
- property->setSetterMethodDecl(SetterMethod);
- }
- // Add any synthesized methods to the global pool. This allows us to
- // handle the following, which is supported by GCC (and part of the design).
- //
- // @interface Foo
- // @property double bar;
- // @end
- //
- // void thisIsUnfortunate() {
- // id foo;
- // double bar = [foo bar];
- // }
- //
- if (GetterMethod)
- AddInstanceMethodToGlobalPool(GetterMethod);
- if (SetterMethod)
- AddInstanceMethodToGlobalPool(SetterMethod);
-}
-
/// CompareMethodParamsInBaseAndSuper - This routine compares methods with
/// identical selector names in current and its super classes and issues
/// a warning if any of their argument types are incompatible.
@@ -2106,501 +1597,6 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
return DeclPtrTy::make(ObjCMethod);
}
-void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
- SourceLocation Loc,
- unsigned &Attributes) {
- // FIXME: Improve the reported location.
-
- // readonly and readwrite/assign/retain/copy conflict.
- if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
- ObjCDeclSpec::DQ_PR_assign |
- ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain))) {
- const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ?
- "readwrite" :
- (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
- "assign" :
- (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
- "copy" : "retain";
-
- Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
- diag::err_objc_property_attr_mutually_exclusive :
- diag::warn_objc_property_attr_mutually_exclusive)
- << "readonly" << which;
- }
-
- // Check for copy or retain on non-object types.
- if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
- !PropertyTy->isObjCObjectPointerType() &&
- !PropertyTy->isBlockPointerType() &&
- !Context.isObjCNSObjectType(PropertyTy)) {
- Diag(Loc, diag::err_objc_property_requires_object)
- << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
- Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
- }
-
- // Check for more than one of { assign, copy, retain }.
- if (Attributes & ObjCDeclSpec::DQ_PR_assign) {
- if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "assign" << "copy";
- Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
- }
- if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "assign" << "retain";
- Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
- }
- } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
- if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "copy" << "retain";
- Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
- }
- }
-
- // Warn if user supplied no assignment attribute, property is
- // readwrite, and this is an object type.
- if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain)) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- PropertyTy->isObjCObjectPointerType()) {
- // Skip this warning in gc-only mode.
- if (getLangOptions().getGCMode() != LangOptions::GCOnly)
- Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
-
- // If non-gc code warn that this is likely inappropriate.
- if (getLangOptions().getGCMode() == LangOptions::NonGC)
- Diag(Loc, diag::warn_objc_property_default_assign_on_object);
-
- // FIXME: Implement warning dependent on NSCopying being
- // implemented. See also:
- // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
- // (please trim this list while you are at it).
- }
-
- if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)
- && getLangOptions().getGCMode() == LangOptions::GCOnly
- && PropertyTy->isBlockPointerType())
- Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
-}
-
-Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
- FieldDeclarator &FD,
- ObjCDeclSpec &ODS,
- Selector GetterSel,
- Selector SetterSel,
- DeclPtrTy ClassCategory,
- bool *isOverridingProperty,
- tok::ObjCKeywordKind MethodImplKind) {
- unsigned Attributes = ODS.getPropertyAttributes();
- bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
- // default is readwrite!
- !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
- // property is defaulted to 'assign' if it is readwrite and is
- // not retain or copy
- bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
- (isReadWrite &&
- !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_copy)));
- QualType T = GetTypeForDeclarator(FD.D, S);
- if (T->isReferenceType()) {
- Diag(AtLoc, diag::error_reference_property);
- return DeclPtrTy();
- }
- Decl *ClassDecl = ClassCategory.getAs<Decl>();
- ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class
- // May modify Attributes.
- CheckObjCPropertyAttributes(T, AtLoc, Attributes);
- if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
- if (CDecl->IsClassExtension()) {
- // Diagnose if this property is already in continuation class.
- DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
- assert(DC && "ClassDecl is not a DeclContext");
- DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier());
- if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
- Diag(AtLoc, diag::err_duplicate_property);
- Diag((*Found.first)->getLocation(), diag::note_property_declare);
- return DeclPtrTy();
- }
- ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
- FD.D.getIdentifierLoc(),
- FD.D.getIdentifier(),
- AtLoc, T);
- DC->addDecl(PDecl);
-
- // This is a continuation class. property requires special
- // handling.
- if ((CCPrimary = CDecl->getClassInterface())) {
- // Find the property in continuation class's primary class only.
- IdentifierInfo *PropertyId = FD.D.getIdentifier();
- if (ObjCPropertyDecl *PIDecl =
- CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId)) {
- // property 'PIDecl's readonly attribute will be over-ridden
- // with continuation class's readwrite property attribute!
- unsigned PIkind = PIDecl->getPropertyAttributes();
- if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
- unsigned retainCopyNonatomic =
- (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_copy |
- ObjCPropertyDecl::OBJC_PR_nonatomic);
- if ((Attributes & retainCopyNonatomic) !=
- (PIkind & retainCopyNonatomic)) {
- 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) {
- // Protocol is not in the primary class. Must build one for it.
- ObjCDeclSpec ProtocolPropertyODS;
- // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind and
- // ObjCPropertyDecl::PropertyAttributeKind have identical values.
- // Should consolidate both into one enum type.
- ProtocolPropertyODS.setPropertyAttributes(
- (ObjCDeclSpec::ObjCPropertyAttributeKind)PIkind);
- DeclPtrTy ProtocolPtrTy =
- ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS,
- PIDecl->getGetterName(),
- PIDecl->getSetterName(),
- DeclPtrTy::make(CCPrimary), isOverridingProperty,
- MethodImplKind);
- PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>();
- }
- PIDecl->makeitReadWriteAttribute();
- if (Attributes & ObjCDeclSpec::DQ_PR_retain)
- PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
- if (Attributes & ObjCDeclSpec::DQ_PR_copy)
- PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
- PIDecl->setSetterName(SetterSel);
- } else {
- Diag(AtLoc, diag::err_use_continuation_class)
- << CCPrimary->getDeclName();
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
- *isOverridingProperty = true;
- // Make sure setter decl is synthesized, and added to primary
- // class's list.
- ProcessPropertyDecl(PIDecl, CCPrimary);
- return DeclPtrTy();
- }
-
- // No matching property found in the primary class. Just fall thru
- // and add property to continuation class's primary class.
- ClassDecl = CCPrimary;
- } else {
- Diag(CDecl->getLocation(), diag::err_continuation_class);
- *isOverridingProperty = true;
- return DeclPtrTy();
- }
- }
-
- // Issue a warning if property is 'assign' as default and its object, which is
- // gc'able conforms to NSCopying protocol
- if (getLangOptions().getGCMode() != LangOptions::NonGC &&
- isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
- if (T->isObjCObjectPointerType()) {
- QualType InterfaceTy = T->getPointeeType();
- if (const ObjCInterfaceType *OIT =
- InterfaceTy->getAs<ObjCInterfaceType>()) {
- ObjCInterfaceDecl *IDecl = OIT->getDecl();
- if (IDecl)
- if (ObjCProtocolDecl* PNSCopying =
- LookupProtocol(&Context.Idents.get("NSCopying")))
- if (IDecl->ClassImplementsProtocol(PNSCopying, true))
- Diag(AtLoc, diag::warn_implements_nscopying)
- << FD.D.getIdentifier();
- }
- }
- if (T->isObjCInterfaceType())
- Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object);
-
- DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
- assert(DC && "ClassDecl is not a DeclContext");
- ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
- FD.D.getIdentifierLoc(),
- FD.D.getIdentifier(),
- AtLoc, T);
- DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName());
- if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
- Diag(PDecl->getLocation(), diag::err_duplicate_property);
- Diag((*Found.first)->getLocation(), diag::note_property_declare);
- PDecl->setInvalidDecl();
- }
- else
- DC->addDecl(PDecl);
-
- if (T->isArrayType() || T->isFunctionType()) {
- Diag(AtLoc, diag::err_property_type) << T;
- PDecl->setInvalidDecl();
- }
-
- ProcessDeclAttributes(S, PDecl, FD.D);
-
- // Regardless of setter/getter attribute, we save the default getter/setter
- // selector names in anticipation of declaration of setter/getter methods.
- PDecl->setGetterName(GetterSel);
- PDecl->setSetterName(SetterSel);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_getter)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_setter)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
-
- if (isReadWrite)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_retain)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_copy)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
-
- if (isAssign)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
-
- if (MethodImplKind == tok::objc_required)
- PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
- else if (MethodImplKind == tok::objc_optional)
- PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
- // A case of continuation class adding a new property in the class. This
- // is not what it was meant for. However, gcc supports it and so should we.
- // Make sure setter/getters are declared here.
- if (CCPrimary)
- ProcessPropertyDecl(PDecl, CCPrimary);
-
- return DeclPtrTy::make(PDecl);
-}
-
-ObjCIvarDecl*
-Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
- IdentifierInfo *NameII) {
- ObjCIvarDecl *Ivar = 0;
- ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII);
- if (Prop && !Prop->isInvalidDecl()) {
- DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl);
- QualType PropType = Context.getCanonicalType(Prop->getType());
- assert(EnclosingContext &&
- "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar");
- Ivar = ObjCIvarDecl::Create(Context, EnclosingContext,
- Prop->getLocation(),
- NameII, PropType, /*Dinfo=*/0,
- ObjCIvarDecl::Public,
- (Expr *)0);
- Ivar->setLexicalDeclContext(IDecl);
- IDecl->addDecl(Ivar);
- Prop->setPropertyIvarDecl(Ivar);
- }
- return Ivar;
-}
-
-/// ActOnPropertyImplDecl - This routine performs semantic checks and
-/// builds the AST node for a property implementation declaration; declared
-/// as @synthesize or @dynamic.
-///
-Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
- SourceLocation PropertyLoc,
- bool Synthesize,
- DeclPtrTy ClassCatImpDecl,
- IdentifierInfo *PropertyId,
- IdentifierInfo *PropertyIvar) {
- Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>();
- // Make sure we have a context for the property implementation declaration.
- if (!ClassImpDecl) {
- Diag(AtLoc, diag::error_missing_property_context);
- return DeclPtrTy();
- }
- ObjCPropertyDecl *property = 0;
- ObjCInterfaceDecl* IDecl = 0;
- // Find the class or category class where this property must have
- // a declaration.
- ObjCImplementationDecl *IC = 0;
- ObjCCategoryImplDecl* CatImplClass = 0;
- if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
- IDecl = IC->getClassInterface();
- // We always synthesize an interface for an implementation
- // without an interface decl. So, IDecl is always non-zero.
- assert(IDecl &&
- "ActOnPropertyImplDecl - @implementation without @interface");
-
- // Look for this property declaration in the @implementation's @interface
- property = IDecl->FindPropertyDeclaration(PropertyId);
- if (!property) {
- Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
- return DeclPtrTy();
- }
- if (const ObjCCategoryDecl *CD =
- dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
- if (!CD->IsClassExtension()) {
- Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
- Diag(property->getLocation(), diag::note_property_declare);
- return DeclPtrTy();
- }
- }
- } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
- if (Synthesize) {
- Diag(AtLoc, diag::error_synthesize_category_decl);
- return DeclPtrTy();
- }
- IDecl = CatImplClass->getClassInterface();
- if (!IDecl) {
- Diag(AtLoc, diag::error_missing_property_interface);
- return DeclPtrTy();
- }
- ObjCCategoryDecl *Category =
- IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
-
- // If category for this implementation not found, it is an error which
- // has already been reported eralier.
- if (!Category)
- return DeclPtrTy();
- // Look for this property declaration in @implementation's category
- property = Category->FindPropertyDeclaration(PropertyId);
- if (!property) {
- Diag(PropertyLoc, diag::error_bad_category_property_decl)
- << Category->getDeclName();
- return DeclPtrTy();
- }
- } else {
- Diag(AtLoc, diag::error_bad_property_context);
- return DeclPtrTy();
- }
- ObjCIvarDecl *Ivar = 0;
- // Check that we have a valid, previously declared ivar for @synthesize
- if (Synthesize) {
- // @synthesize
- if (!PropertyIvar)
- PropertyIvar = PropertyId;
- QualType PropType = Context.getCanonicalType(property->getType());
- // Check that this is a previously declared 'ivar' in 'IDecl' interface
- ObjCInterfaceDecl *ClassDeclared;
- Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
- if (!Ivar) {
- DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl);
- assert(EnclosingContext &&
- "null DeclContext for synthesized ivar - ActOnPropertyImplDecl");
- Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc,
- PropertyIvar, PropType, /*Dinfo=*/0,
- ObjCIvarDecl::Public,
- (Expr *)0);
- IDecl->makeDeclVisibleInContext(Ivar, false);
- property->setPropertyIvarDecl(Ivar);
- if (!getLangOptions().ObjCNonFragileABI)
- Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
- // Note! I deliberately want it to fall thru so, we have a
- // a property implementation and to avoid future warnings.
- } else if (getLangOptions().ObjCNonFragileABI &&
- ClassDeclared != IDecl) {
- Diag(PropertyLoc, diag::error_ivar_in_superclass_use)
- << property->getDeclName() << Ivar->getDeclName()
- << ClassDeclared->getDeclName();
- Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
- << Ivar << Ivar->getNameAsCString();
- // Note! I deliberately want it to fall thru so more errors are caught.
- }
- QualType IvarType = Context.getCanonicalType(Ivar->getType());
-
- // Check that type of property and its ivar are type compatible.
- if (PropType != IvarType) {
- if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
- Diag(PropertyLoc, diag::error_property_ivar_type)
- << property->getDeclName() << Ivar->getDeclName();
- // Note! I deliberately want it to fall thru so, we have a
- // a property implementation and to avoid future warnings.
- }
-
- // FIXME! Rules for properties are somewhat different that those
- // for assignments. Use a new routine to consolidate all cases;
- // specifically for property redeclarations as well as for ivars.
- QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType();
- QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
- if (lhsType != rhsType &&
- lhsType->isArithmeticType()) {
- Diag(PropertyLoc, diag::error_property_ivar_type)
- << property->getDeclName() << Ivar->getDeclName();
- // Fall thru - see previous comment
- }
- // __weak is explicit. So it works on Canonical type.
- if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
- getLangOptions().getGCMode() != LangOptions::NonGC) {
- Diag(PropertyLoc, diag::error_weak_property)
- << property->getDeclName() << Ivar->getDeclName();
- // Fall thru - see previous comment
- }
- if ((property->getType()->isObjCObjectPointerType() ||
- PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
- getLangOptions().getGCMode() != LangOptions::NonGC) {
- Diag(PropertyLoc, diag::error_strong_property)
- << property->getDeclName() << Ivar->getDeclName();
- // Fall thru - see previous comment
- }
- }
- } else if (PropertyIvar)
- // @dynamic
- Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
- assert (property && "ActOnPropertyImplDecl - property declaration missing");
- ObjCPropertyImplDecl *PIDecl =
- ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
- property,
- (Synthesize ?
- ObjCPropertyImplDecl::Synthesize
- : ObjCPropertyImplDecl::Dynamic),
- Ivar);
- if (IC) {
- if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
- IC->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::error_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
- << PropertyIvar;
- Diag(PPIDecl->getLocation(), diag::note_previous_use);
- }
-
- if (ObjCPropertyImplDecl *PPIDecl
- = IC->FindPropertyImplDecl(PropertyId)) {
- Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
- Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
- return DeclPtrTy();
- }
- IC->addPropertyImplementation(PIDecl);
- } else {
- if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
- CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::error_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
- << PropertyIvar;
- Diag(PPIDecl->getLocation(), diag::note_previous_use);
- }
-
- if (ObjCPropertyImplDecl *PPIDecl =
- CatImplClass->FindPropertyImplDecl(PropertyId)) {
- Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
- Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
- return DeclPtrTy();
- }
- CatImplClass->addPropertyImplementation(PIDecl);
- }
-
- return DeclPtrTy::make(PIDecl);
-}
-
bool Sema::CheckObjCDeclScope(Decl *D) {
if (isa<TranslationUnitDecl>(CurContext->getLookupContext()))
return false;
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 9be411b552ad..4ce1ce9b019f 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -294,12 +294,12 @@ bool Sema::CheckExceptionSpecSubset(
continue;
// Do this check from a context without privileges.
- switch (CheckBaseClassAccess(SourceLocation(), false,
+ switch (CheckBaseClassAccess(SourceLocation(),
CanonicalSuperT, CanonicalSubT,
Paths.front(),
+ /*Diagnostic*/ 0,
/*ForceCheck*/ true,
- /*ForceUnprivileged*/ true,
- ADK_quiet)) {
+ /*ForceUnprivileged*/ true)) {
case AR_accessible: break;
case AR_inaccessible: continue;
case AR_dependent:
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 2249579ba4e1..a39ba2f7d06e 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -58,7 +58,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
Diag(Loc, diag::warn_unavailable) << D->getDeclName();
Diag(D->getLocation(), diag::note_unavailable_here) << 0;
}
-
+
// See if this is a deleted function.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
@@ -202,7 +202,7 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) {
DefaultFunctionArrayConversion(E);
-
+
QualType Ty = E->getType();
assert(!Ty.isNull() && "DefaultFunctionArrayLvalueConversion - missing type");
if (!Ty->isDependentType() && Ty.hasQualifiers() &&
@@ -214,8 +214,8 @@ void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) {
// rvalue is T
//
// C99 6.3.2.1p2:
- // If the lvalue has qualified type, the value has the unqualified
- // version of the type of the lvalue; otherwise, the value has the
+ // If the lvalue has qualified type, the value has the unqualified
+ // version of the type of the lvalue; otherwise, the value has the
// type of the lvalue.
ImpCastExprToType(E, Ty.getUnqualifiedType(), CastExpr::CK_NoOp);
}
@@ -289,7 +289,7 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
return true;
if (!Expr->getType()->isPODType() &&
- DiagRuntimeBehavior(Expr->getLocStart(),
+ DiagRuntimeBehavior(Expr->getLocStart(),
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
<< Expr->getType() << CT))
return true;
@@ -370,7 +370,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
if (Literal.Pascal) StrTy = Context.UnsignedCharTy;
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
- if (getLangOptions().CPlusPlus)
+ if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings )
StrTy.addConst();
// Get an array type for the string, according to C99 6.4.5. This includes
@@ -423,10 +423,10 @@ static bool ShouldSnapshotBlockValueReference(Sema &S, BlockScopeInfo *CurBlock,
// all get the bit). Walk the nesting chain.
for (unsigned I = S.FunctionScopes.size() - 1; I; --I) {
BlockScopeInfo *NextBlock = dyn_cast<BlockScopeInfo>(S.FunctionScopes[I]);
-
+
if (!NextBlock)
continue;
-
+
// If we found the defining block for the variable, don't mark the block as
// having a reference outside it.
if (NextBlock->TheDecl == VD->getDeclContext())
@@ -469,9 +469,9 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc,
MarkDeclarationReferenced(Loc, D);
- return Owned(DeclRefExpr::Create(Context,
- SS? (NestedNameSpecifier *)SS->getScopeRep() : 0,
- SS? SS->getRange() : SourceRange(),
+ return Owned(DeclRefExpr::Create(Context,
+ SS? (NestedNameSpecifier *)SS->getScopeRep() : 0,
+ SS? SS->getRange() : SourceRange(),
D, Loc, Ty));
}
@@ -768,14 +768,14 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
return true;
}
-
+
/// Determines if this is an instance member of a class.
static bool IsInstanceMember(NamedDecl *D) {
assert(D->isCXXClassMember() &&
"checking whether non-member is instance member");
if (isa<FieldDecl>(D)) return true;
-
+
if (isa<CXXMethodDecl>(D))
return !cast<CXXMethodDecl>(D)->isStatic();
@@ -971,7 +971,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
- else
+ else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << computeDeclContext(SS, false) << R.getLookupName()
<< SS.getRange()
@@ -980,7 +980,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
Diag(ND->getLocation(), diag::note_previous_decl)
<< ND->getDeclName();
-
+
// Tell the callee to try to recover.
return false;
}
@@ -993,7 +993,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
// to recover well anyway.
if (SS.isEmpty())
Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
- else
+ else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << computeDeclContext(SS, false) << R.getLookupName()
<< SS.getRange();
@@ -1107,7 +1107,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// If we found an Objective-C instance variable, let
// LookupInObjCMethod build the appropriate expression to
- // reference the ivar.
+ // reference the ivar.
if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) {
R.clear();
OwningExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier()));
@@ -1303,7 +1303,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
// turn this into Self->ivar, just return a BareIVarExpr or something.
IdentifierInfo &II = Context.Idents.get("self");
UnqualifiedId SelfName;
- SelfName.setIdentifier(&II, SourceLocation());
+ SelfName.setIdentifier(&II, SourceLocation());
CXXScopeSpec SelfScopeSpec;
OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec,
SelfName, false, false);
@@ -1326,7 +1326,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
// Needed to implement property "super.method" notation.
if (Lookup.empty() && II->isStr("super")) {
QualType T;
-
+
if (getCurMethodDecl()->isInstanceMethod())
T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
getCurMethodDecl()->getClassInterface()));
@@ -1363,7 +1363,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext());
if (!RD)
return false;
-
+
QualType DestRecordType;
QualType DestType;
QualType FromRecordType;
@@ -1371,7 +1371,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
bool PointerConversions = false;
if (isa<FieldDecl>(Member)) {
DestRecordType = Context.getCanonicalType(Context.getTypeDeclType(RD));
-
+
if (FromType->getAs<PointerType>()) {
DestType = Context.getPointerType(DestRecordType);
FromRecordType = FromType->getPointeeType();
@@ -1383,10 +1383,10 @@ Sema::PerformObjectMemberConversion(Expr *&From,
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) {
if (Method->isStatic())
return false;
-
+
DestType = Method->getThisType(Context);
DestRecordType = DestType->getPointeeType();
-
+
if (FromType->getAs<PointerType>()) {
FromRecordType = FromType->getPointeeType();
PointerConversions = true;
@@ -1398,16 +1398,16 @@ Sema::PerformObjectMemberConversion(Expr *&From,
// No conversion necessary.
return false;
}
-
+
if (DestType->isDependentType() || FromType->isDependentType())
return false;
-
+
// If the unqualified types are the same, no conversion is necessary.
if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
return false;
-
+
// C++ [class.member.lookup]p8:
- // [...] Ambiguities can often be resolved by qualifying a name with its
+ // [...] Ambiguities can often be resolved by qualifying a name with its
// class name.
//
// If the member was a qualified name and the qualified referred to a
@@ -1435,7 +1435,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
IntermediateType = Context.getPointerType(IntermediateType);
}
}
-
+
if (!IntermediateType.isNull() &&
IsDerivedFrom(FromRecordType, IntermediateRecordType) &&
IsDerivedFrom(IntermediateRecordType, DestRecordType)) {
@@ -1448,18 +1448,18 @@ Sema::PerformObjectMemberConversion(Expr *&From,
return true;
ImpCastExprToType(From, IntermediateType, CastExpr::CK_DerivedToBase,
- /*isLvalue=*/!PointerConversions);
+ /*isLvalue=*/!PointerConversions);
ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
/*isLvalue=*/!PointerConversions);
return false;
}
-
+
if (CheckDerivedToBaseConversion(FromRecordType,
DestRecordType,
From->getSourceRange().getBegin(),
From->getSourceRange()))
return true;
-
+
ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
/*isLvalue=*/true);
return false;
@@ -1633,7 +1633,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
return Owned(ULE);
}
-
+
/// \brief Complete semantic analysis for a reference to the given declaration.
Sema::OwningExprResult
@@ -1658,7 +1658,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// Make sure that we're referring to a value.
ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (!VD) {
- Diag(Loc, diag::err_ref_non_value)
+ Diag(Loc, diag::err_ref_non_value)
<< D << SS.getRange();
Diag(D->getLocation(), diag::note_declared_at);
return ExprError();
@@ -1683,7 +1683,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// We do not do this for things like enum constants, global variables, etc,
// as they do not get snapshotted.
//
- if (getCurBlock() &&
+ if (getCurBlock() &&
ShouldSnapshotBlockValueReference(*this, getCurBlock(), VD)) {
if (VD->getType().getTypePtr()->isVariablyModifiedType()) {
Diag(Loc, diag::err_ref_vm_type);
@@ -1819,7 +1819,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
if ((result & APFloat::opOverflow) ||
((result & APFloat::opUnderflow) && Val.isZero())) {
unsigned diagnostic;
- llvm::SmallVector<char, 20> buffer;
+ llvm::SmallString<20> buffer;
if (result & APFloat::opOverflow) {
diagnostic = diag::warn_float_overflow;
APFloat::getLargest(Format).toString(buffer);
@@ -2531,7 +2531,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
}
assert(DC && "Cannot handle non-computable dependent contexts in lookup");
-
+
if (!isa<TypeDecl>(DC)) {
SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
<< DC << SS.getRange();
@@ -2548,7 +2548,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// We didn't find anything with the given name, so try to correct
// for typos.
DeclarationName Name = R.getLookupName();
- if (SemaRef.CorrectTypo(R, 0, &SS, DC) &&
+ if (SemaRef.CorrectTypo(R, 0, &SS, DC) &&
(isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << DC << R.getLookupName() << SS.getRange()
@@ -2685,7 +2685,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
return Owned(MemExpr);
}
- assert(R.isSingleResult());
+ assert(R.isSingleResult());
NamedDecl *MemberDecl = R.getFoundDecl();
// FIXME: diagnose the presence of template arguments now.
@@ -2831,13 +2831,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
Diag(Loc, diag::err_member_reference_needs_call)
<< QualType(Fun, 0)
<< CodeModificationHint::CreateInsertion(Loc, "()");
-
+
OwningExprResult NewBase
- = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc,
+ = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc,
MultiExprArg(*this, 0, 0), 0, Loc);
if (NewBase.isInvalid())
return ExprError();
-
+
BaseExpr = NewBase.takeAs<Expr>();
DefaultFunctionArrayConversion(BaseExpr);
BaseType = BaseExpr->getType();
@@ -2907,20 +2907,20 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Look through local category implementations associated with the class.
if (!Setter)
Setter = IFace->getCategoryClassMethod(SetterSel);
-
+
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
-
+
if (Getter || Setter) {
QualType PType;
-
+
if (Getter)
PType = Getter->getResultType();
else
// Get the expression type from Setter's incoming parameter.
PType = (*(Setter->param_end() -1))->getType();
// FIXME: we must check that the setter has property type.
- return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter,
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter,
PType,
Setter, MemberLoc, BaseExpr));
}
@@ -2928,7 +2928,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
<< MemberName << BaseType);
}
}
-
+
if (BaseType->isObjCClassType() &&
BaseType != Context.ObjCClassRedefinitionType) {
BaseType = Context.ObjCClassRedefinitionType;
@@ -2975,7 +2975,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
}
}
}
-
+
// Handle field access to simple records. This also handles access
// to fields of the ObjC 'id' struct.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
@@ -3005,13 +3005,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
LookupMemberName);
if (CorrectTypo(Res, 0, 0, IDecl) &&
(IV = Res.getAsSingle<ObjCIvarDecl>())) {
- Diag(R.getNameLoc(),
+ Diag(R.getNameLoc(),
diag::err_typecheck_member_reference_ivar_suggest)
<< IDecl->getDeclName() << MemberName << IV->getDeclName()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
IV->getNameAsString());
Diag(IV->getLocation(), diag::note_previous_decl)
- << IV->getDeclName();
+ << IV->getDeclName();
}
}
@@ -3179,7 +3179,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Attempt to correct for typos in property names.
LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
LookupOrdinaryName);
- if (CorrectTypo(Res, 0, 0, IFace, false, OPT) &&
+ if (CorrectTypo(Res, 0, 0, IFace, false, OPT) &&
Res.getAsSingle<ObjCPropertyDecl>()) {
Diag(R.getNameLoc(), diag::err_property_not_found_suggest)
<< MemberName << BaseType << Res.getLookupName()
@@ -3187,7 +3187,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
Res.getLookupName().getAsString());
ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
Diag(Property->getLocation(), diag::note_previous_decl)
- << Property->getDeclName();
+ << Property->getDeclName();
return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl);
@@ -3216,7 +3216,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, *Member,
MemberLoc));
}
-
+
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr->getSourceRange();
@@ -3341,11 +3341,11 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
Expr *ResultE = Result.takeAs<Expr>();
InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1);
- Result = InitSeq.Perform(*this, Entity, Kind,
+ Result = InitSeq.Perform(*this, Entity, Kind,
MultiExprArg(*this, (void**)&ResultE, 1));
if (Result.isInvalid())
return ExprError();
-
+
// Build the default argument expression.
return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param,
Result.takeAs<Expr>()));
@@ -3380,7 +3380,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// assignment, to the types of the corresponding parameter, ...
unsigned NumArgsInProto = Proto->getNumArgs();
bool Invalid = false;
-
+
// If too few arguments are available (and we don't have default
// arguments for the remaining parameters), don't make the call.
if (NumArgs < NumArgsInProto) {
@@ -3405,7 +3405,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
}
}
llvm::SmallVector<Expr *, 8> AllArgs;
- VariadicCallType CallType =
+ VariadicCallType CallType =
Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
if (Fn->getType()->isBlockPointerType())
CallType = VariadicBlock; // Block
@@ -3418,7 +3418,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
unsigned TotalNumArgs = AllArgs.size();
for (unsigned i = 0; i < TotalNumArgs; ++i)
Call->setArg(i, AllArgs[i]);
-
+
return false;
}
@@ -3439,23 +3439,23 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
// Continue to check argument types (even if we have too few/many args).
for (unsigned i = FirstProtoArg; i != NumArgsToCheck; i++) {
QualType ProtoArgType = Proto->getArgType(i);
-
+
Expr *Arg;
if (ArgIx < NumArgs) {
Arg = Args[ArgIx++];
-
+
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
ProtoArgType,
PDiag(diag::err_call_incomplete_argument)
<< Arg->getSourceRange()))
return true;
-
+
// Pass the argument
ParmVarDecl *Param = 0;
if (FDecl && i < FDecl->getNumParams())
Param = FDecl->getParamDecl(i);
-
+
InitializedEntity Entity =
Param? InitializedEntity::InitializeParameter(Param)
: InitializedEntity::InitializeParameter(ProtoArgType);
@@ -3468,17 +3468,17 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
Arg = ArgE.takeAs<Expr>();
} else {
ParmVarDecl *Param = FDecl->getParamDecl(i);
-
+
OwningExprResult ArgExpr =
BuildCXXDefaultArgExpr(CallLoc, FDecl, Param);
if (ArgExpr.isInvalid())
return true;
-
+
Arg = ArgExpr.takeAs<Expr>();
}
AllArgs.push_back(Arg);
}
-
+
// If this is a variadic call, handle args passed through "...".
if (CallType != VariadicDoesNotApply) {
// Promote the arguments (C99 6.5.2.2p7).
@@ -3570,32 +3570,32 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc);
}
-
+
// Determine whether this is a call to a pointer-to-member function.
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(NakedFn)) {
if (BO->getOpcode() == BinaryOperator::PtrMemD ||
BO->getOpcode() == BinaryOperator::PtrMemI) {
- if (const FunctionProtoType *FPT =
+ if (const FunctionProtoType *FPT =
dyn_cast<FunctionProtoType>(BO->getType())) {
QualType ResultTy = FPT->getResultType().getNonReferenceType();
-
- ExprOwningPtr<CXXMemberCallExpr>
- TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args,
+
+ ExprOwningPtr<CXXMemberCallExpr>
+ TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args,
NumArgs, ResultTy,
RParenLoc));
-
- if (CheckCallReturnType(FPT->getResultType(),
- BO->getRHS()->getSourceRange().getBegin(),
+
+ if (CheckCallReturnType(FPT->getResultType(),
+ BO->getRHS()->getSourceRange().getBegin(),
TheCall.get(), 0))
return ExprError();
- if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs,
+ if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs,
RParenLoc))
return ExprError();
return Owned(MaybeBindToTemporary(TheCall.release()).release());
}
- return ExprError(Diag(Fn->getLocStart(),
+ return ExprError(Diag(Fn->getLocStart(),
diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
}
@@ -3661,7 +3661,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
<< Fn->getType() << Fn->getSourceRange());
// Check for a valid return type
- if (CheckCallReturnType(FuncT->getResultType(),
+ if (CheckCallReturnType(FuncT->getResultType(),
Fn->getSourceRange().getBegin(), TheCall.get(),
FDecl))
return ExprError();
@@ -3762,7 +3762,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
InitializedEntity Entity
= InitializedEntity::InitializeTemporary(literalType);
InitializationKind Kind
- = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc),
+ = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc),
/*IsCStyleCast=*/true);
InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1);
OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
@@ -3780,7 +3780,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
}
Result.release();
-
+
return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
literalExpr, isFileScope));
}
@@ -3807,13 +3807,13 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context,
if (SrcTy->hasPointerRepresentation()) {
if (DestTy->hasPointerRepresentation())
- return DestTy->isObjCObjectPointerType() ?
- CastExpr::CK_AnyPointerToObjCPointerCast :
+ return DestTy->isObjCObjectPointerType() ?
+ CastExpr::CK_AnyPointerToObjCPointerCast :
CastExpr::CK_BitCast;
if (DestTy->isIntegerType())
return CastExpr::CK_PointerToIntegral;
}
-
+
if (SrcTy->isIntegerType()) {
if (DestTy->isIntegerType())
return CastExpr::CK_IntegralCast;
@@ -3822,14 +3822,14 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context,
if (DestTy->isRealFloatingType())
return CastExpr::CK_IntegralToFloating;
}
-
+
if (SrcTy->isRealFloatingType()) {
if (DestTy->isRealFloatingType())
return CastExpr::CK_FloatingCast;
if (DestTy->isIntegerType())
return CastExpr::CK_FloatingToIntegral;
}
-
+
// FIXME: Assert here.
// assert(false && "Unhandled cast combination!");
return CastExpr::CK_Unknown;
@@ -3853,7 +3853,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
Kind = CastExpr::CK_ToVoid;
return false;
}
-
+
if (!castType->isScalarType() && !castType->isVectorType()) {
if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) &&
(castType->isStructureType() || castType->isUnionType())) {
@@ -3864,14 +3864,14 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
Kind = CastExpr::CK_NoOp;
return false;
}
-
+
if (castType->isUnionType()) {
// GCC cast to union extension
RecordDecl *RD = castType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator Field, FieldEnd;
for (Field = RD->field_begin(), FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
- if (Context.hasSameUnqualifiedType(Field->getType(),
+ if (Context.hasSameUnqualifiedType(Field->getType(),
castExpr->getType())) {
Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union)
<< castExpr->getSourceRange();
@@ -3884,22 +3884,22 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
Kind = CastExpr::CK_ToUnion;
return false;
}
-
+
// Reject any other conversions to non-scalar types.
return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
<< castType << castExpr->getSourceRange();
}
-
- if (!castExpr->getType()->isScalarType() &&
+
+ if (!castExpr->getType()->isScalarType() &&
!castExpr->getType()->isVectorType()) {
return Diag(castExpr->getLocStart(),
diag::err_typecheck_expect_scalar_operand)
<< castExpr->getType() << castExpr->getSourceRange();
}
-
- if (castType->isExtVectorType())
+
+ if (castType->isExtVectorType())
return CheckExtVectorCast(TyR, castType, castExpr, Kind);
-
+
if (castType->isVectorType())
return CheckVectorCast(TyR, castType, castExpr->getType(), Kind);
if (castExpr->getType()->isVectorType())
@@ -3907,10 +3907,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr))
return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR;
-
+
if (isa<ObjCSelectorExpr>(castExpr))
return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr);
-
+
if (!castType->isArithmeticType()) {
QualType castExprType = castExpr->getType();
if (!castExprType->isIntegralType() && castExprType->isArithmeticType())
@@ -3948,12 +3948,12 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
return false;
}
-bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr,
+bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr,
CastExpr::CastKind &Kind) {
assert(DestTy->isExtVectorType() && "Not an extended vector type!");
-
+
QualType SrcTy = CastExpr->getType();
-
+
// If SrcTy is a VectorType, the total size must match to explicitly cast to
// an ExtVectorType.
if (SrcTy->isVectorType()) {
@@ -3975,7 +3975,7 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr,
QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType();
ImpCastExprToType(CastExpr, DestElemTy,
getScalarCastKind(Context, SrcTy, DestElemTy));
-
+
Kind = CastExpr::CK_VectorSplat;
return false;
}
@@ -4105,7 +4105,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (getLangOptions().CPlusPlus)
return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc);
- CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional);
+ CheckSignCompare(LHS, RHS, QuestionLoc);
UsualUnaryConversions(Cond);
UsualUnaryConversions(LHS);
@@ -4169,14 +4169,14 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown);
return RHSTy;
}
-
+
// All objective-c pointer type analysis is done here.
QualType compositeType = FindCompositeObjCPointerType(LHS, RHS,
QuestionLoc);
if (!compositeType.isNull())
return compositeType;
-
-
+
+
// Handle block pointer types.
if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
@@ -4198,7 +4198,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// The block pointer types aren't identical, continue checking.
QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType();
QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType();
-
+
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
@@ -4216,7 +4216,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
return LHSTy;
}
-
+
// Check constraints for C object pointers types (C99 6.5.15p3,6).
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
// get the "pointed to" types
@@ -4300,7 +4300,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
SourceLocation QuestionLoc) {
QualType LHSTy = LHS->getType();
QualType RHSTy = RHS->getType();
-
+
// Handle things like Class and struct objc_class*. Here we case the result
// to the pseudo-builtin, because that will be implicitly cast back to the
// redefinition type if an attempt is made to access its fields.
@@ -4338,7 +4338,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
}
// Check constraints for Objective-C object pointers types.
if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) {
-
+
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
// Two identical object pointer types are always compatible.
return LHSTy;
@@ -4346,7 +4346,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>();
QualType compositeType = LHSTy;
-
+
// If both operands are interfaces and either operand can be
// assigned to the other, use that type as the composite
// type. This allows
@@ -4357,7 +4357,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
// allow silent coercion. Finally, if the types are
// incompatible then make sure to use 'id' as the composite
// type so the result is acceptable for sending messages to.
-
+
// FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
// It could return the composite type.
if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) {
@@ -4374,7 +4374,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
compositeType = Context.getObjCIdType();
} else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) {
compositeType = Context.getObjCIdType();
- } else if (!(compositeType =
+ } else if (!(compositeType =
Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull())
;
else {
@@ -4512,7 +4512,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
lhptee = Context.UnsignedCharTy;
else if (lhptee->isSignedIntegerType())
lhptee = Context.getCorrespondingUnsignedType(lhptee);
-
+
if (rhptee->isCharType())
rhptee = Context.UnsignedCharTy;
else if (rhptee->isSignedIntegerType())
@@ -4526,7 +4526,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
return ConvTy;
return IncompatiblePointerSign;
}
-
+
// If we are a multi-level pointer, it's possible that our issue is simply
// one of qualification - e.g. char ** -> const char ** is not allowed. If
// the eventual target type is the same and the pointers have the same
@@ -4535,15 +4535,15 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
do {
lhptee = lhptee->getAs<PointerType>()->getPointeeType();
rhptee = rhptee->getAs<PointerType>()->getPointeeType();
-
+
lhptee = Context.getCanonicalType(lhptee);
rhptee = Context.getCanonicalType(rhptee);
} while (lhptee->isPointerType() && rhptee->isPointerType());
-
+
if (Context.hasSameUnqualifiedType(lhptee, rhptee))
return IncompatibleNestedPointerQualifiers;
}
-
+
// General pointer incompatibility takes priority over qualifiers.
return IncompatiblePointer;
}
@@ -4584,21 +4584,21 @@ Sema::AssignConvertType
Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType())
return Compatible;
- QualType lhptee =
+ QualType lhptee =
lhsType->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType rhptee =
+ QualType rhptee =
rhsType->getAs<ObjCObjectPointerType>()->getPointeeType();
// make sure we operate on the canonical type
lhptee = Context.getCanonicalType(lhptee);
rhptee = Context.getCanonicalType(rhptee);
if (!lhptee.isAtLeastAsQualifiedAs(rhptee))
return CompatiblePointerDiscardsQualifiers;
-
+
if (Context.typesAreCompatible(lhsType, rhsType))
return Compatible;
if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
return IncompatibleObjCQualifiedId;
- return IncompatiblePointer;
+ return IncompatiblePointer;
}
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
@@ -4824,7 +4824,7 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
break;
}
- if (rExpr->isNullPointerConstant(Context,
+ if (rExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_IntegralToPointer);
InitField = *it;
@@ -4868,7 +4868,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
if ((lhsType->isPointerType() ||
lhsType->isObjCObjectPointerType() ||
lhsType->isBlockPointerType())
- && rExpr->isNullPointerConstant(Context,
+ && rExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(rExpr, lhsType, CastExpr::CK_Unknown);
return Compatible;
@@ -4976,13 +4976,13 @@ QualType Sema::CheckMultiplyDivideOperands(
if (!lex->getType()->isArithmeticType() ||
!rex->getType()->isArithmeticType())
return InvalidOperands(Loc, lex, rex);
-
+
// Check for division by zero.
if (isDiv &&
rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero)
+ DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero)
<< rex->getSourceRange());
-
+
return compType;
}
@@ -4998,12 +4998,12 @@ QualType Sema::CheckRemainderOperands(
if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType())
return InvalidOperands(Loc, lex, rex);
-
+
// Check for remainder by zero.
if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
DiagRuntimeBehavior(Loc, PDiag(diag::warn_remainder_by_zero)
<< rex->getSourceRange());
-
+
return compType;
}
@@ -5282,8 +5282,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
- CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison,
- (Opc == BinaryOperator::EQ || Opc == BinaryOperator::NE));
+ CheckSignCompare(lex, rex, Loc, &Opc);
// C99 6.5.8p3 / C99 6.5.9p4
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
@@ -5320,13 +5319,13 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
Expr *literalString = 0;
Expr *literalStringStripped = 0;
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
- !RHSStripped->isNullPointerConstant(Context,
+ !RHSStripped->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
literalString = lex;
literalStringStripped = LHSStripped;
} else if ((isa<StringLiteral>(RHSStripped) ||
isa<ObjCEncodeExpr>(RHSStripped)) &&
- !LHSStripped->isNullPointerConstant(Context,
+ !LHSStripped->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
literalString = rex;
literalStringStripped = RHSStripped;
@@ -5343,7 +5342,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
case BinaryOperator::NE: resultComparison = ") != 0"; break;
default: assert(false && "Invalid comparison operator");
}
-
+
DiagRuntimeBehavior(Loc,
PDiag(diag::warn_stringcompare)
<< isa<ObjCEncodeExpr>(literalStringStripped)
@@ -5372,9 +5371,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return ResultTy;
}
- bool LHSIsNull = lex->isNullPointerConstant(Context,
+ bool LHSIsNull = lex->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
- bool RHSIsNull = rex->isNullPointerConstant(Context,
+ bool RHSIsNull = rex->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
// All of the following pointer related warnings are GCC extensions, except
@@ -5417,9 +5416,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
return QualType();
} else if (NonStandardCompositeType) {
- Diag(Loc,
+ Diag(Loc,
diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
- << lType << rType << T
+ << lType << rType << T
<< lex->getSourceRange() << rex->getSourceRange();
}
@@ -5490,9 +5489,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
return QualType();
} else if (NonStandardCompositeType) {
- Diag(Loc,
+ Diag(Loc,
diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
- << lType << rType << T
+ << lType << rType << T
<< lex->getSourceRange() << rex->getSourceRange();
}
@@ -5678,10 +5677,10 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType())
return InvalidOperands(Loc, lex, rex);
-
+
return Context.IntTy;
}
-
+
// C++ [expr.log.and]p1
// C++ [expr.log.or]p1
// The operands are both implicitly converted to type bool (clause 4).
@@ -5693,16 +5692,16 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
if (PerformImplicitConversion(lex, Context.BoolTy, LHS,
AA_Passing, /*IgnoreBaseAccess=*/false))
return InvalidOperands(Loc, lex, rex);
-
+
StandardConversionSequence RHS;
if (!IsStandardConversion(rex, Context.BoolTy,
/*InOverloadResolution=*/false, RHS))
return InvalidOperands(Loc, lex, rex);
-
+
if (PerformImplicitConversion(rex, Context.BoolTy, RHS,
AA_Passing, /*IgnoreBaseAccess=*/false))
return InvalidOperands(Loc, lex, rex);
-
+
// C++ [expr.log.and]p2
// C++ [expr.log.or]p2
// The result is a bool.
@@ -6342,10 +6341,10 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
Self.Diag(Loc, PD)
<< CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
<< CodeModificationHint::CreateInsertion(EndLoc, ")");
-
+
if (!SecondPD.getDiagID())
return;
-
+
EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
// We can't display the parentheses, so just dig the
@@ -6353,7 +6352,7 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
Self.Diag(Loc, SecondPD);
return;
}
-
+
Self.Diag(Loc, SecondPD)
<< CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(")
<< CodeModificationHint::CreateInsertion(EndLoc, ")");
@@ -6443,12 +6442,12 @@ Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
if (S && OverOp != OO_None)
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
Functions);
-
+
// Build the (potentially-overloaded, potentially-dependent)
// binary operation.
return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs);
}
-
+
// Build a built-in binary operation.
return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs);
}
@@ -6556,10 +6555,10 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
if (S && OverOp != OO_None)
LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
Functions);
-
+
return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input));
}
-
+
return CreateBuiltinUnaryOp(OpLoc, Opc, move(input));
}
@@ -6819,7 +6818,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
BlockScopeInfo *CurBlock = getCurBlock();
-
+
if (ParamInfo.getNumTypeObjects() == 0
|| ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
@@ -6986,13 +6985,13 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
PopFunctionOrBlockScope();
return ExprError();
}
-
+
AnalysisContext AC(BSI->TheDecl);
CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
CheckUnreachable(AC);
Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs);
- PopFunctionOrBlockScope();
+ PopFunctionOrBlockScope();
return Owned(Result);
}
@@ -7049,14 +7048,14 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
}
-static void
+static void
MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef,
QualType DstType,
Expr *SrcExpr,
CodeModificationHint &Hint) {
if (!SemaRef.getLangOptions().ObjC1)
return;
-
+
const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>();
if (!PT)
return;
@@ -7068,12 +7067,12 @@ MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef,
if (!ID || !ID->getIdentifier()->isStr("NSString"))
return;
}
-
+
// Strip off any parens and casts.
StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts());
if (!SL || SL->isWide())
return;
-
+
Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@");
}
@@ -7085,7 +7084,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
bool isInvalid = false;
unsigned DiagKind;
CodeModificationHint Hint;
-
+
switch (ConvTy) {
default: assert(0 && "Unknown conversion type");
case Compatible: return false;
@@ -7202,7 +7201,7 @@ Sema::PopExpressionEvaluationContext() {
// Mark any remaining declarations in the current position of the stack
// as "referenced". If they were not meant to be referenced, semantic
// analysis would have eliminated them (e.g., in ActOnCXXTypeId).
- for (PotentiallyReferencedDecls::iterator
+ for (PotentiallyReferencedDecls::iterator
I = Rec.PotentiallyReferenced->begin(),
IEnd = Rec.PotentiallyReferenced->end();
I != IEnd; ++I)
@@ -7217,13 +7216,13 @@ Sema::PopExpressionEvaluationContext() {
I != IEnd; ++I)
Diag(I->first, I->second);
}
- }
+ }
// When are coming out of an unevaluated context, clear out any
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
// will never be constructed.
- if (Rec.Context == Unevaluated &&
+ if (Rec.Context == Unevaluated &&
ExprTemporaries.size() > Rec.NumTemporaries)
ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries,
ExprTemporaries.end());
@@ -7252,7 +7251,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
// template or not. The reason for this is that unevaluated expressions
// (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and
// -Wunused-parameters)
- if (isa<ParmVarDecl>(D) ||
+ if (isa<ParmVarDecl>(D) ||
(isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod()))
D->setUsed(true);
@@ -7290,7 +7289,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (!Constructor->isUsed())
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
-
+
MaybeMarkVirtualMembersReferenced(Loc, Constructor);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
if (Destructor->isImplicit() && !Destructor->isUsed())
@@ -7312,32 +7311,32 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
= Function->getTemplateSpecializationInfo()) {
if (SpecInfo->getPointOfInstantiation().isInvalid())
SpecInfo->setPointOfInstantiation(Loc);
- else if (SpecInfo->getTemplateSpecializationKind()
+ else if (SpecInfo->getTemplateSpecializationKind()
== TSK_ImplicitInstantiation)
AlreadyInstantiated = true;
- } else if (MemberSpecializationInfo *MSInfo
+ } else if (MemberSpecializationInfo *MSInfo
= Function->getMemberSpecializationInfo()) {
if (MSInfo->getPointOfInstantiation().isInvalid())
MSInfo->setPointOfInstantiation(Loc);
- else if (MSInfo->getTemplateSpecializationKind()
+ else if (MSInfo->getTemplateSpecializationKind()
== TSK_ImplicitInstantiation)
AlreadyInstantiated = true;
}
-
+
if (!AlreadyInstantiated) {
if (isa<CXXRecordDecl>(Function->getDeclContext()) &&
cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
Loc));
else
- PendingImplicitInstantiations.push_back(std::make_pair(Function,
+ PendingImplicitInstantiations.push_back(std::make_pair(Function,
Loc));
}
}
-
+
// FIXME: keep track of references to static functions
Function->setUsed(true);
-
+
return;
}
@@ -7365,29 +7364,29 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
/// of the program being compiled.
///
/// This routine emits the given diagnostic when the code currently being
-/// type-checked is "potentially evaluated", meaning that there is a
+/// type-checked is "potentially evaluated", meaning that there is a
/// possibility that the code will actually be executable. Code in sizeof()
/// expressions, code used only during overload resolution, etc., are not
/// potentially evaluated. This routine will suppress such diagnostics or,
/// in the absolutely nutty case of potentially potentially evaluated
-/// expressions (C++ typeid), queue the diagnostic to potentially emit it
+/// expressions (C++ typeid), queue the diagnostic to potentially emit it
/// later.
-///
+///
/// This routine should be used for all diagnostics that describe the run-time
/// behavior of a program, such as passing a non-POD value through an ellipsis.
/// Failure to do so will likely result in spurious diagnostics or failures
/// during overload resolution or within sizeof/alignof/typeof/typeid.
-bool Sema::DiagRuntimeBehavior(SourceLocation Loc,
+bool Sema::DiagRuntimeBehavior(SourceLocation Loc,
const PartialDiagnostic &PD) {
switch (ExprEvalContexts.back().Context ) {
case Unevaluated:
// The argument will never be evaluated, so don't complain.
break;
-
+
case PotentiallyEvaluated:
Diag(Loc, PD);
return true;
-
+
case PotentiallyPotentiallyEvaluated:
ExprEvalContexts.back().addDiagnostic(Loc, PD);
break;
@@ -7405,12 +7404,12 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here)
<< FD->getDeclName() : PDiag();
SourceLocation NoteLoc = FD ? FD->getLocation() : SourceLocation();
-
+
if (RequireCompleteType(Loc, ReturnType,
- FD ?
+ FD ?
PDiag(diag::err_call_function_incomplete_return)
<< CE->getSourceRange() << FD->getDeclName() :
- PDiag(diag::err_call_incomplete_return)
+ PDiag(diag::err_call_incomplete_return)
<< CE->getSourceRange(),
std::make_pair(NoteLoc, Note)))
return true;
@@ -7460,7 +7459,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
SourceLocation Open = E->getSourceRange().getBegin();
SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
-
+
Diag(Loc, diagnostic)
<< E->getSourceRange()
<< CodeModificationHint::CreateInsertion(Open, "(")
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index b9c8afa195fd..e1e5efa7d3a9 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -2085,7 +2085,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (LHS->isTypeDependent() || RHS->isTypeDependent())
return Context.DependentTy;
- CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional);
+ CheckSignCompare(LHS, RHS, QuestionLoc);
// C++0x 5.16p2
// If either the second or the third operand has type (cv) void, ...
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index c60455d8456c..c98ba435c789 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -106,7 +106,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
// which is an array type.
StrTy = Context.CharTy;
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
- if (getLangOptions().CPlusPlus)
+ if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings)
StrTy.addConst();
StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1),
ArrayType::Normal, 0);
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 3540cd02e6da..98a7eec232f6 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -1051,6 +1051,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
bool InitializedSomething = false;
+ bool CheckForMissingFields = true;
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
@@ -1070,6 +1071,10 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
hadError = true;
InitializedSomething = true;
+
+ // Disable check for missing fields when designators are used.
+ // This matches gcc behaviour.
+ CheckForMissingFields = false;
continue;
}
@@ -1106,6 +1111,21 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
++Field;
}
+ // Emit warnings for missing struct field initializers.
+ if (CheckForMissingFields && Field != FieldEnd &&
+ !Field->getType()->isIncompleteArrayType() && !DeclType->isUnionType()) {
+ // It is possible we have one or more unnamed bitfields remaining.
+ // Find first (if any) named field and emit warning.
+ for (RecordDecl::field_iterator it = Field, end = RD->field_end();
+ it != end; ++it) {
+ if (!it->isUnnamedBitfield()) {
+ SemaRef.Diag(IList->getSourceRange().getEnd(),
+ diag::warn_missing_field_initializers) << it->getName();
+ break;
+ }
+ }
+ }
+
if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() ||
Index >= IList->getNumInits())
return;
@@ -3381,7 +3401,7 @@ InitializationSequence::Perform(Sema &S,
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
- S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr,
+ S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0,
Conversion, FnAccess);
// FIXME: Should we move this initialization into a separate
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 744b80632848..6caeec620d01 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -590,13 +590,73 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
return false;
}
-// Find the next outer declaration context corresponding to this scope.
-static DeclContext *findOuterContext(Scope *S) {
- for (S = S->getParent(); S; S = S->getParent())
- if (S->getEntity())
- return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
+// Find the next outer declaration context from this scope. This
+// routine actually returns the semantic outer context, which may
+// differ from the lexical context (encoded directly in the Scope
+// stack) when we are parsing a member of a class template. In this
+// case, the second element of the pair will be true, to indicate that
+// name lookup should continue searching in this semantic context when
+// it leaves the current template parameter scope.
+static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
+ DeclContext *DC = static_cast<DeclContext *>(S->getEntity());
+ DeclContext *Lexical = 0;
+ for (Scope *OuterS = S->getParent(); OuterS;
+ OuterS = OuterS->getParent()) {
+ if (OuterS->getEntity()) {
+ Lexical = static_cast<DeclContext *>(OuterS->getEntity());
+ break;
+ }
+ }
+
+ // C++ [temp.local]p8:
+ // In the definition of a member of a class template that appears
+ // outside of the namespace containing the class template
+ // definition, the name of a template-parameter hides the name of
+ // a member of this namespace.
+ //
+ // Example:
+ //
+ // namespace N {
+ // class C { };
+ //
+ // template<class T> class B {
+ // void f(T);
+ // };
+ // }
+ //
+ // template<class C> void N::B<C>::f(C) {
+ // C b; // C is the template parameter, not N::C
+ // }
+ //
+ // In this example, the lexical context we return is the
+ // TranslationUnit, while the semantic context is the namespace N.
+ if (!Lexical || !DC || !S->getParent() ||
+ !S->getParent()->isTemplateParamScope())
+ return std::make_pair(Lexical, false);
+
+ // Find the outermost template parameter scope.
+ // For the example, this is the scope for the template parameters of
+ // template<class C>.
+ Scope *OutermostTemplateScope = S->getParent();
+ while (OutermostTemplateScope->getParent() &&
+ OutermostTemplateScope->getParent()->isTemplateParamScope())
+ OutermostTemplateScope = OutermostTemplateScope->getParent();
- return 0;
+ // Find the namespace context in which the original scope occurs. In
+ // the example, this is namespace N.
+ DeclContext *Semantic = DC;
+ while (!Semantic->isFileContext())
+ Semantic = Semantic->getParent();
+
+ // Find the declaration context just outside of the template
+ // parameter scope. This is the context in which the template is
+ // being lexically declaration (a namespace context). In the
+ // example, this is the global scope.
+ if (Lexical->isFileContext() && !Lexical->Equals(Semantic) &&
+ Lexical->Encloses(Semantic))
+ return std::make_pair(Semantic, true);
+
+ return std::make_pair(Lexical, false);
}
bool Sema::CppLookupName(LookupResult &R, Scope *S) {
@@ -627,6 +687,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// }
// }
//
+ DeclContext *OutsideOfTemplateParamDC = 0;
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
// Check whether the IdResolver has anything in this scope.
bool Found = false;
@@ -641,10 +702,26 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return true;
}
- if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
- DeclContext *OuterCtx = findOuterContext(S);
- for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
- Ctx = Ctx->getLookupParent()) {
+ DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
+ S->getParent() && !S->getParent()->isTemplateParamScope()) {
+ // We've just searched the last template parameter scope and
+ // found nothing, so look into the the contexts between the
+ // lexical and semantic declaration contexts returned by
+ // findOuterContext(). This implements the name lookup behavior
+ // of C++ [temp.local]p8.
+ Ctx = OutsideOfTemplateParamDC;
+ OutsideOfTemplateParamDC = 0;
+ }
+
+ if (Ctx) {
+ DeclContext *OuterCtx;
+ bool SearchAfterTemplateScope;
+ llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
+ if (SearchAfterTemplateScope)
+ OutsideOfTemplateParamDC = OuterCtx;
+
+ for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) {
// We do not directly look into transparent contexts, since
// those entities will be found in the nearest enclosing
// non-transparent context.
@@ -725,7 +802,10 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
}
}
- if (Ctx) {
+ // If we have a context, and it's not a context stashed in the
+ // template parameter scope for an out-of-line definition, also
+ // look into that context.
+ if (Ctx && !(Found && S && S->isTemplateParamScope())) {
assert(Ctx->isFileContext() &&
"We should have been looking only at file context here already.");
@@ -2216,15 +2296,16 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
}
}
+ // FIXME: C++ [temp.local]p8
DeclContext *Entity = 0;
if (S->getEntity()) {
// Look into this scope's declaration context, along with any of its
// parent lookup contexts (e.g., enclosing classes), up to the point
// where we hit the context stored in the next outer scope.
Entity = (DeclContext *)S->getEntity();
- DeclContext *OuterCtx = findOuterContext(S);
+ DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
- for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx;
+ for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
Ctx = Ctx->getLookupParent()) {
if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) {
if (Method->isInstanceMethod()) {
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
new file mode 100644
index 000000000000..3a0fe0a61afe
--- /dev/null
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -0,0 +1,1085 @@
+//===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for Objective C @property and
+// @synthesize declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Grammar actions.
+//===----------------------------------------------------------------------===//
+
+Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
+ FieldDeclarator &FD,
+ ObjCDeclSpec &ODS,
+ Selector GetterSel,
+ Selector SetterSel,
+ DeclPtrTy ClassCategory,
+ bool *isOverridingProperty,
+ tok::ObjCKeywordKind MethodImplKind) {
+ unsigned Attributes = ODS.getPropertyAttributes();
+ bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
+ // default is readwrite!
+ !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
+ // property is defaulted to 'assign' if it is readwrite and is
+ // not retain or copy
+ bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
+ (isReadWrite &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_copy)));
+
+ QualType T = GetTypeForDeclarator(FD.D, S);
+ if (T->isReferenceType()) {
+ Diag(AtLoc, diag::error_reference_property);
+ return DeclPtrTy();
+ }
+ // Validate the attributes on the @property.
+ CheckObjCPropertyAttributes(T, AtLoc, Attributes);
+
+ // Proceed with constructing the ObjCPropertDecls.
+ ObjCContainerDecl *ClassDecl =
+ cast<ObjCContainerDecl>(ClassCategory.getAs<Decl>());
+
+ if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
+ if (CDecl->IsClassExtension())
+ return HandlePropertyInClassExtension(S, CDecl, AtLoc,
+ FD, GetterSel, SetterSel,
+ isAssign, isReadWrite,
+ Attributes,
+ isOverridingProperty, T,
+ MethodImplKind);
+
+ return DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
+ GetterSel, SetterSel,
+ isAssign, isReadWrite,
+ Attributes, T, MethodImplKind));
+}
+
+Sema::DeclPtrTy
+Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
+ SourceLocation AtLoc, FieldDeclarator &FD,
+ Selector GetterSel, Selector SetterSel,
+ const bool isAssign,
+ const bool isReadWrite,
+ const unsigned Attributes,
+ bool *isOverridingProperty,
+ QualType T,
+ tok::ObjCKeywordKind MethodImplKind) {
+
+ // Diagnose if this property is already in continuation class.
+ DeclContext *DC = cast<DeclContext>(CDecl);
+ IdentifierInfo *PropertyId = FD.D.getIdentifier();
+
+ if (ObjCPropertyDecl *prevDecl =
+ ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) {
+ Diag(AtLoc, diag::err_duplicate_property);
+ Diag(prevDecl->getLocation(), diag::note_property_declare);
+ return DeclPtrTy();
+ }
+
+ // Create a new ObjCPropertyDecl with the DeclContext being
+ // the class extension.
+ ObjCPropertyDecl *PDecl =
+ ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(),
+ PropertyId, AtLoc, T);
+ DC->addDecl(PDecl);
+
+ // We need to look in the @interface to see if the @property was
+ // already declared.
+ ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
+ if (!CCPrimary) {
+ Diag(CDecl->getLocation(), diag::err_continuation_class);
+ *isOverridingProperty = true;
+ return DeclPtrTy();
+ }
+
+ // Find the property in continuation class's primary class only.
+ ObjCPropertyDecl *PIDecl =
+ CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId);
+
+ if (!PIDecl) {
+ // No matching property found in the primary class. Just fall thru
+ // and add property to continuation class's primary class.
+ ObjCPropertyDecl *PDecl =
+ CreatePropertyDecl(S, CCPrimary, AtLoc,
+ FD, GetterSel, SetterSel, isAssign, isReadWrite,
+ Attributes, T, MethodImplKind);
+
+ // A case of continuation class adding a new property in the class. This
+ // is not what it was meant for. However, gcc supports it and so should we.
+ // Make sure setter/getters are declared here.
+ ProcessPropertyDecl(PDecl, CCPrimary);
+ return DeclPtrTy::make(PDecl);
+
+ }
+
+ // The property 'PIDecl's readonly attribute will be over-ridden
+ // with continuation class's readwrite property attribute!
+ unsigned PIkind = PIDecl->getPropertyAttributes();
+ if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
+ unsigned retainCopyNonatomic =
+ (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_copy |
+ ObjCPropertyDecl::OBJC_PR_nonatomic);
+ if ((Attributes & retainCopyNonatomic) !=
+ (PIkind & retainCopyNonatomic)) {
+ 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) {
+ // Protocol is not in the primary class. Must build one for it.
+ ObjCDeclSpec ProtocolPropertyODS;
+ // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind
+ // and ObjCPropertyDecl::PropertyAttributeKind have identical
+ // values. Should consolidate both into one enum type.
+ ProtocolPropertyODS.
+ setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind)
+ PIkind);
+
+ DeclPtrTy ProtocolPtrTy =
+ ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS,
+ PIDecl->getGetterName(),
+ PIDecl->getSetterName(),
+ DeclPtrTy::make(CCPrimary), isOverridingProperty,
+ MethodImplKind);
+ PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>();
+ }
+ PIDecl->makeitReadWriteAttribute();
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+ PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+ PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+ PIDecl->setSetterName(SetterSel);
+ } else {
+ Diag(AtLoc, diag::err_use_continuation_class)
+ << CCPrimary->getDeclName();
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
+ *isOverridingProperty = true;
+ // Make sure setter decl is synthesized, and added to primary class's list.
+ ProcessPropertyDecl(PIDecl, CCPrimary);
+ return DeclPtrTy();
+}
+
+ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
+ ObjCContainerDecl *CDecl,
+ SourceLocation AtLoc,
+ FieldDeclarator &FD,
+ Selector GetterSel,
+ Selector SetterSel,
+ const bool isAssign,
+ const bool isReadWrite,
+ const unsigned Attributes,
+ QualType T,
+ tok::ObjCKeywordKind MethodImplKind){
+
+ IdentifierInfo *PropertyId = FD.D.getIdentifier();
+
+ // Issue a warning if property is 'assign' as default and its object, which is
+ // gc'able conforms to NSCopying protocol
+ if (getLangOptions().getGCMode() != LangOptions::NonGC &&
+ isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
+ if (T->isObjCObjectPointerType()) {
+ QualType InterfaceTy = T->getPointeeType();
+ if (const ObjCInterfaceType *OIT =
+ InterfaceTy->getAs<ObjCInterfaceType>()) {
+ ObjCInterfaceDecl *IDecl = OIT->getDecl();
+ if (IDecl)
+ if (ObjCProtocolDecl* PNSCopying =
+ LookupProtocol(&Context.Idents.get("NSCopying")))
+ if (IDecl->ClassImplementsProtocol(PNSCopying, true))
+ Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
+ }
+ }
+ if (T->isObjCInterfaceType())
+ Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object);
+
+ DeclContext *DC = cast<DeclContext>(CDecl);
+ ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
+ FD.D.getIdentifierLoc(),
+ PropertyId, AtLoc, T);
+
+ if (ObjCPropertyDecl *prevDecl =
+ ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) {
+ Diag(PDecl->getLocation(), diag::err_duplicate_property);
+ Diag(prevDecl->getLocation(), diag::note_property_declare);
+ PDecl->setInvalidDecl();
+ }
+ else
+ DC->addDecl(PDecl);
+
+ if (T->isArrayType() || T->isFunctionType()) {
+ Diag(AtLoc, diag::err_property_type) << T;
+ PDecl->setInvalidDecl();
+ }
+
+ ProcessDeclAttributes(S, PDecl, FD.D);
+
+ // Regardless of setter/getter attribute, we save the default getter/setter
+ // selector names in anticipation of declaration of setter/getter methods.
+ PDecl->setGetterName(GetterSel);
+ PDecl->setSetterName(SetterSel);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_getter)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_setter)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
+
+ if (isReadWrite)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+
+ if (isAssign)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
+
+ if (MethodImplKind == tok::objc_required)
+ PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
+ else if (MethodImplKind == tok::objc_optional)
+ PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
+
+ return PDecl;
+}
+
+
+/// ActOnPropertyImplDecl - This routine performs semantic checks and
+/// builds the AST node for a property implementation declaration; declared
+/// as @synthesize or @dynamic.
+///
+Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
+ SourceLocation PropertyLoc,
+ bool Synthesize,
+ DeclPtrTy ClassCatImpDecl,
+ IdentifierInfo *PropertyId,
+ IdentifierInfo *PropertyIvar) {
+ Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>();
+ // Make sure we have a context for the property implementation declaration.
+ if (!ClassImpDecl) {
+ Diag(AtLoc, diag::error_missing_property_context);
+ return DeclPtrTy();
+ }
+ ObjCPropertyDecl *property = 0;
+ ObjCInterfaceDecl* IDecl = 0;
+ // Find the class or category class where this property must have
+ // a declaration.
+ ObjCImplementationDecl *IC = 0;
+ ObjCCategoryImplDecl* CatImplClass = 0;
+ if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
+ IDecl = IC->getClassInterface();
+ // We always synthesize an interface for an implementation
+ // without an interface decl. So, IDecl is always non-zero.
+ assert(IDecl &&
+ "ActOnPropertyImplDecl - @implementation without @interface");
+
+ // Look for this property declaration in the @implementation's @interface
+ property = IDecl->FindPropertyDeclaration(PropertyId);
+ if (!property) {
+ Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
+ return DeclPtrTy();
+ }
+ if (const ObjCCategoryDecl *CD =
+ dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
+ if (!CD->IsClassExtension()) {
+ Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
+ Diag(property->getLocation(), diag::note_property_declare);
+ return DeclPtrTy();
+ }
+ }
+ } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
+ if (Synthesize) {
+ Diag(AtLoc, diag::error_synthesize_category_decl);
+ return DeclPtrTy();
+ }
+ IDecl = CatImplClass->getClassInterface();
+ if (!IDecl) {
+ Diag(AtLoc, diag::error_missing_property_interface);
+ return DeclPtrTy();
+ }
+ ObjCCategoryDecl *Category =
+ IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
+
+ // If category for this implementation not found, it is an error which
+ // has already been reported eralier.
+ if (!Category)
+ return DeclPtrTy();
+ // Look for this property declaration in @implementation's category
+ property = Category->FindPropertyDeclaration(PropertyId);
+ if (!property) {
+ Diag(PropertyLoc, diag::error_bad_category_property_decl)
+ << Category->getDeclName();
+ return DeclPtrTy();
+ }
+ } else {
+ Diag(AtLoc, diag::error_bad_property_context);
+ return DeclPtrTy();
+ }
+ ObjCIvarDecl *Ivar = 0;
+ // Check that we have a valid, previously declared ivar for @synthesize
+ if (Synthesize) {
+ // @synthesize
+ if (!PropertyIvar)
+ PropertyIvar = PropertyId;
+ QualType PropType = Context.getCanonicalType(property->getType());
+ // Check that this is a previously declared 'ivar' in 'IDecl' interface
+ ObjCInterfaceDecl *ClassDeclared;
+ Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
+ if (!Ivar) {
+ DeclContext *EnclosingContext = cast_or_null<DeclContext>(ClassImpDecl);
+ assert(EnclosingContext &&
+ "null DeclContext for synthesized ivar - ActOnPropertyImplDecl");
+ Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc,
+ PropertyIvar, PropType, /*Dinfo=*/0,
+ ObjCIvarDecl::Public,
+ (Expr *)0);
+ EnclosingContext->addDecl(Ivar);
+ IDecl->makeDeclVisibleInContext(Ivar, false);
+ property->setPropertyIvarDecl(Ivar);
+
+ if (!getLangOptions().ObjCNonFragileABI)
+ Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
+ // Note! I deliberately want it to fall thru so, we have a
+ // a property implementation and to avoid future warnings.
+ } else if (getLangOptions().ObjCNonFragileABI &&
+ ClassDeclared != IDecl) {
+ Diag(PropertyLoc, diag::error_ivar_in_superclass_use)
+ << property->getDeclName() << Ivar->getDeclName()
+ << ClassDeclared->getDeclName();
+ Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
+ << Ivar << Ivar->getNameAsCString();
+ // Note! I deliberately want it to fall thru so more errors are caught.
+ }
+ QualType IvarType = Context.getCanonicalType(Ivar->getType());
+
+ // Check that type of property and its ivar are type compatible.
+ if (PropType != IvarType) {
+ if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
+ Diag(PropertyLoc, diag::error_property_ivar_type)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Note! I deliberately want it to fall thru so, we have a
+ // a property implementation and to avoid future warnings.
+ }
+
+ // FIXME! Rules for properties are somewhat different that those
+ // for assignments. Use a new routine to consolidate all cases;
+ // specifically for property redeclarations as well as for ivars.
+ QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType();
+ QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
+ if (lhsType != rhsType &&
+ lhsType->isArithmeticType()) {
+ Diag(PropertyLoc, diag::error_property_ivar_type)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Fall thru - see previous comment
+ }
+ // __weak is explicit. So it works on Canonical type.
+ if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
+ getLangOptions().getGCMode() != LangOptions::NonGC) {
+ Diag(PropertyLoc, diag::error_weak_property)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Fall thru - see previous comment
+ }
+ if ((property->getType()->isObjCObjectPointerType() ||
+ PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
+ getLangOptions().getGCMode() != LangOptions::NonGC) {
+ Diag(PropertyLoc, diag::error_strong_property)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Fall thru - see previous comment
+ }
+ }
+ } else if (PropertyIvar)
+ // @dynamic
+ Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
+ assert (property && "ActOnPropertyImplDecl - property declaration missing");
+ ObjCPropertyImplDecl *PIDecl =
+ ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
+ property,
+ (Synthesize ?
+ ObjCPropertyImplDecl::Synthesize
+ : ObjCPropertyImplDecl::Dynamic),
+ Ivar);
+ if (IC) {
+ if (Synthesize)
+ if (ObjCPropertyImplDecl *PPIDecl =
+ IC->FindPropertyImplIvarDecl(PropertyIvar)) {
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ << PropertyIvar;
+ Diag(PPIDecl->getLocation(), diag::note_previous_use);
+ }
+
+ if (ObjCPropertyImplDecl *PPIDecl
+ = IC->FindPropertyImplDecl(PropertyId)) {
+ Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
+ Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
+ return DeclPtrTy();
+ }
+ IC->addPropertyImplementation(PIDecl);
+ } else {
+ if (Synthesize)
+ if (ObjCPropertyImplDecl *PPIDecl =
+ CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ << PropertyIvar;
+ Diag(PPIDecl->getLocation(), diag::note_previous_use);
+ }
+
+ if (ObjCPropertyImplDecl *PPIDecl =
+ CatImplClass->FindPropertyImplDecl(PropertyId)) {
+ Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
+ Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
+ return DeclPtrTy();
+ }
+ CatImplClass->addPropertyImplementation(PIDecl);
+ }
+
+ return DeclPtrTy::make(PIDecl);
+}
+
+//===----------------------------------------------------------------------===//
+// Helper methods.
+//===----------------------------------------------------------------------===//
+
+/// DiagnosePropertyMismatch - Compares two properties for their
+/// attributes and types and warns on a variety of inconsistencies.
+///
+void
+Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
+ ObjCPropertyDecl *SuperProperty,
+ const IdentifierInfo *inheritedName) {
+ ObjCPropertyDecl::PropertyAttributeKind CAttr =
+ Property->getPropertyAttributes();
+ ObjCPropertyDecl::PropertyAttributeKind SAttr =
+ SuperProperty->getPropertyAttributes();
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
+ && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
+ Diag(Property->getLocation(), diag::warn_readonly_property)
+ << Property->getDeclName() << inheritedName;
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "copy" << inheritedName;
+ else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain)
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "retain" << inheritedName;
+
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "atomic" << inheritedName;
+ if (Property->getSetterName() != SuperProperty->getSetterName())
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "setter" << inheritedName;
+ if (Property->getGetterName() != SuperProperty->getGetterName())
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "getter" << inheritedName;
+
+ QualType LHSType =
+ Context.getCanonicalType(SuperProperty->getType());
+ QualType RHSType =
+ Context.getCanonicalType(Property->getType());
+
+ if (!Context.typesAreCompatible(LHSType, RHSType)) {
+ // FIXME: Incorporate this test with typesAreCompatible.
+ if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
+ if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
+ return;
+ Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
+ << Property->getType() << SuperProperty->getType() << inheritedName;
+ }
+}
+
+bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
+ ObjCMethodDecl *GetterMethod,
+ SourceLocation Loc) {
+ if (GetterMethod &&
+ GetterMethod->getResultType() != property->getType()) {
+ AssignConvertType result = Incompatible;
+ if (property->getType()->isObjCObjectPointerType())
+ result = CheckAssignmentConstraints(GetterMethod->getResultType(),
+ property->getType());
+ if (result != Compatible) {
+ Diag(Loc, diag::warn_accessor_property_type_mismatch)
+ << property->getDeclName()
+ << GetterMethod->getSelector();
+ Diag(GetterMethod->getLocation(), diag::note_declared_at);
+ return true;
+ }
+ }
+ return false;
+}
+
+/// ComparePropertiesInBaseAndSuper - This routine compares property
+/// declarations in base and its super class, if any, and issues
+/// diagnostics in a variety of inconsistant situations.
+///
+void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
+ ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
+ if (!SDecl)
+ return;
+ // FIXME: O(N^2)
+ for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(),
+ E = SDecl->prop_end(); S != E; ++S) {
+ ObjCPropertyDecl *SuperPDecl = (*S);
+ // Does property in super class has declaration in current class?
+ for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(),
+ E = IDecl->prop_end(); I != E; ++I) {
+ ObjCPropertyDecl *PDecl = (*I);
+ if (SuperPDecl->getIdentifier() == PDecl->getIdentifier())
+ DiagnosePropertyMismatch(PDecl, SuperPDecl,
+ SDecl->getIdentifier());
+ }
+ }
+}
+
+/// MatchOneProtocolPropertiesInClass - This routine goes thru the list
+/// of properties declared in a protocol and compares their attribute against
+/// the same property declared in the class or category.
+void
+Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
+ ObjCProtocolDecl *PDecl) {
+ ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
+ if (!IDecl) {
+ // Category
+ ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
+ assert (CatDecl && "MatchOneProtocolPropertiesInClass");
+ if (!CatDecl->IsClassExtension())
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Pr = (*P);
+ ObjCCategoryDecl::prop_iterator CP, CE;
+ // Is this property already in category's list of properties?
+ for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP!=CE; ++CP)
+ if ((*CP)->getIdentifier() == Pr->getIdentifier())
+ break;
+ if (CP != CE)
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+ }
+ return;
+ }
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Pr = (*P);
+ ObjCInterfaceDecl::prop_iterator CP, CE;
+ // Is this property already in class's list of properties?
+ for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP)
+ if ((*CP)->getIdentifier() == Pr->getIdentifier())
+ break;
+ if (CP != CE)
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+ }
+}
+
+/// CompareProperties - This routine compares properties
+/// declared in 'ClassOrProtocol' objects (which can be a class or an
+/// inherited protocol with the list of properties for class/category 'CDecl'
+///
+void Sema::CompareProperties(Decl *CDecl,
+ DeclPtrTy ClassOrProtocol) {
+ Decl *ClassDecl = ClassOrProtocol.getAs<Decl>();
+ ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
+
+ if (!IDecl) {
+ // Category
+ ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
+ assert (CatDecl && "CompareProperties");
+ if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
+ for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(),
+ E = MDecl->protocol_end(); P != E; ++P)
+ // Match properties of category with those of protocol (*P)
+ MatchOneProtocolPropertiesInClass(CatDecl, *P);
+
+ // Go thru the list of protocols for this category and recursively match
+ // their properties with those in the category.
+ for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(),
+ E = CatDecl->protocol_end(); P != E; ++P)
+ CompareProperties(CatDecl, DeclPtrTy::make(*P));
+ } else {
+ ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
+ for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
+ E = MD->protocol_end(); P != E; ++P)
+ MatchOneProtocolPropertiesInClass(CatDecl, *P);
+ }
+ return;
+ }
+
+ if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
+ for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
+ E = MDecl->protocol_end(); P != E; ++P)
+ // Match properties of class IDecl with those of protocol (*P).
+ MatchOneProtocolPropertiesInClass(IDecl, *P);
+
+ // Go thru the list of protocols for this class and recursively match
+ // their properties with those declared in the class.
+ for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); P != E; ++P)
+ CompareProperties(IDecl, DeclPtrTy::make(*P));
+ } else {
+ ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
+ for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
+ E = MD->protocol_end(); P != E; ++P)
+ MatchOneProtocolPropertiesInClass(IDecl, *P);
+ }
+}
+
+/// isPropertyReadonly - Return true if property is readonly, by searching
+/// for the property in the class and in its categories and implementations
+///
+bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
+ ObjCInterfaceDecl *IDecl) {
+ // by far the most common case.
+ if (!PDecl->isReadOnly())
+ return false;
+ // Even if property is ready only, if interface has a user defined setter,
+ // it is not considered read only.
+ if (IDecl->getInstanceMethod(PDecl->getSetterName()))
+ return false;
+
+ // Main class has the property as 'readonly'. Must search
+ // through the category list to see if the property's
+ // attribute has been over-ridden to 'readwrite'.
+ for (ObjCCategoryDecl *Category = IDecl->getCategoryList();
+ Category; Category = Category->getNextClassCategory()) {
+ // Even if property is ready only, if a category has a user defined setter,
+ // it is not considered read only.
+ if (Category->getInstanceMethod(PDecl->getSetterName()))
+ return false;
+ ObjCPropertyDecl *P =
+ Category->FindPropertyDeclaration(PDecl->getIdentifier());
+ if (P && !P->isReadOnly())
+ return false;
+ }
+
+ // Also, check for definition of a setter method in the implementation if
+ // all else failed.
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) {
+ if (ObjCImplementationDecl *IMD =
+ dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) {
+ if (IMD->getInstanceMethod(PDecl->getSetterName()))
+ return false;
+ } else if (ObjCCategoryImplDecl *CIMD =
+ dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
+ if (CIMD->getInstanceMethod(PDecl->getSetterName()))
+ return false;
+ }
+ }
+ // Lastly, look through the implementation (if one is in scope).
+ if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation())
+ if (ImpDecl->getInstanceMethod(PDecl->getSetterName()))
+ return false;
+ // If all fails, look at the super class.
+ if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass())
+ return isPropertyReadonly(PDecl, SIDecl);
+ return true;
+}
+
+/// CollectImmediateProperties - This routine collects all properties in
+/// the class and its conforming protocols; but not those it its super class.
+void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+ if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ if (!CATDecl->IsClassExtension())
+ for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
+ E = CATDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
+ E = CATDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+ else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
+ if (!PropEntry)
+ PropEntry = Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+}
+
+/// LookupPropertyDecl - Looks up a property in the current class and all
+/// its protocols.
+ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
+ IdentifierInfo *II) {
+ if (const ObjCInterfaceDecl *IDecl =
+ dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ if (Prop->getIdentifier() == II)
+ return Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI) {
+ ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
+ if (Prop)
+ return Prop;
+ }
+ }
+ else if (const ObjCProtocolDecl *PDecl =
+ dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ if (Prop->getIdentifier() == II)
+ return Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI) {
+ ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
+ if (Prop)
+ return Prop;
+ }
+ }
+ return 0;
+}
+
+
+void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl *CDecl,
+ const llvm::DenseSet<Selector>& InsMap) {
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
+ CollectImmediateProperties(CDecl, PropMap);
+ if (PropMap.empty())
+ return;
+
+ llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
+ for (ObjCImplDecl::propimpl_iterator
+ I = IMPDecl->propimpl_begin(),
+ EI = IMPDecl->propimpl_end(); I != EI; ++I)
+ PropImplMap.insert((*I)->getPropertyDecl());
+
+ for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = P->second;
+ // Is there a matching propery synthesize/dynamic?
+ if (Prop->isInvalidDecl() ||
+ Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
+ PropImplMap.count(Prop))
+ continue;
+ if (LangOpts.ObjCNonFragileABI2) {
+ ActOnPropertyImplDecl(IMPDecl->getLocation(),
+ SourceLocation(),
+ true, DeclPtrTy::make(IMPDecl),
+ Prop->getIdentifier(),
+ Prop->getIdentifier());
+ continue;
+ }
+ if (!InsMap.count(Prop->getGetterName())) {
+ Diag(Prop->getLocation(),
+ isa<ObjCCategoryDecl>(CDecl) ?
+ diag::warn_setter_getter_impl_required_in_category :
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getGetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+
+ if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
+ Diag(Prop->getLocation(),
+ isa<ObjCCategoryDecl>(CDecl) ?
+ diag::warn_setter_getter_impl_required_in_category :
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getSetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+ }
+}
+
+void
+Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* IDecl) {
+ // Rules apply in non-GC mode only
+ if (getLangOptions().getGCMode() != LangOptions::NonGC)
+ return;
+ for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(),
+ E = IDecl->prop_end();
+ I != E; ++I) {
+ ObjCPropertyDecl *Property = (*I);
+ unsigned Attributes = Property->getPropertyAttributes();
+ // We only care about readwrite atomic property.
+ if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) ||
+ !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite))
+ continue;
+ if (const ObjCPropertyImplDecl *PIDecl
+ = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) {
+ if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ ObjCMethodDecl *GetterMethod =
+ IMPDecl->getInstanceMethod(Property->getGetterName());
+ ObjCMethodDecl *SetterMethod =
+ IMPDecl->getInstanceMethod(Property->getSetterName());
+ if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
+ SourceLocation MethodLoc =
+ (GetterMethod ? GetterMethod->getLocation()
+ : SetterMethod->getLocation());
+ Diag(MethodLoc, diag::warn_atomic_property_rule)
+ << Property->getIdentifier();
+ Diag(Property->getLocation(), diag::note_property_declare);
+ }
+ }
+ }
+}
+
+/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
+/// have the property type and issue diagnostics if they don't.
+/// Also synthesize a getter/setter method if none exist (and update the
+/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized
+/// methods is the "right" thing to do.
+void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
+ ObjCContainerDecl *CD) {
+ ObjCMethodDecl *GetterMethod, *SetterMethod;
+
+ GetterMethod = CD->getInstanceMethod(property->getGetterName());
+ SetterMethod = CD->getInstanceMethod(property->getSetterName());
+ DiagnosePropertyAccessorMismatch(property, GetterMethod,
+ property->getLocation());
+
+ if (SetterMethod) {
+ ObjCPropertyDecl::PropertyAttributeKind CAttr =
+ property->getPropertyAttributes();
+ if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) &&
+ Context.getCanonicalType(SetterMethod->getResultType()) !=
+ Context.VoidTy)
+ Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
+ if (SetterMethod->param_size() != 1 ||
+ ((*SetterMethod->param_begin())->getType() != property->getType())) {
+ Diag(property->getLocation(),
+ diag::warn_accessor_property_type_mismatch)
+ << property->getDeclName()
+ << SetterMethod->getSelector();
+ Diag(SetterMethod->getLocation(), diag::note_declared_at);
+ }
+ }
+
+ // Synthesize getter/setter methods if none exist.
+ // Find the default getter and if one not found, add one.
+ // FIXME: The synthesized property we set here is misleading. We almost always
+ // synthesize these methods unless the user explicitly provided prototypes
+ // (which is odd, but allowed). Sema should be typechecking that the
+ // declarations jive in that situation (which it is not currently).
+ if (!GetterMethod) {
+ // No instance method of same name as property getter name was found.
+ // Declare a getter method and add it to the list of methods
+ // for this class.
+ GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
+ property->getLocation(), property->getGetterName(),
+ property->getType(), 0, CD, true, false, true,
+ (property->getPropertyImplementation() ==
+ ObjCPropertyDecl::Optional) ?
+ ObjCMethodDecl::Optional :
+ ObjCMethodDecl::Required);
+ CD->addDecl(GetterMethod);
+ } else
+ // A user declared getter will be synthesize when @synthesize of
+ // the property with the same name is seen in the @implementation
+ GetterMethod->setSynthesized(true);
+ property->setGetterMethodDecl(GetterMethod);
+
+ // Skip setter if property is read-only.
+ if (!property->isReadOnly()) {
+ // Find the default setter and if one not found, add one.
+ if (!SetterMethod) {
+ // No instance method of same name as property setter name was found.
+ // Declare a setter method and add it to the list of methods
+ // for this class.
+ SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
+ property->getLocation(),
+ property->getSetterName(),
+ Context.VoidTy, 0, CD, true, false, true,
+ (property->getPropertyImplementation() ==
+ ObjCPropertyDecl::Optional) ?
+ ObjCMethodDecl::Optional :
+ ObjCMethodDecl::Required);
+ // Invent the arguments for the setter. We don't bother making a
+ // nice name for the argument.
+ ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
+ property->getLocation(),
+ property->getIdentifier(),
+ property->getType(),
+ /*TInfo=*/0,
+ VarDecl::None,
+ 0);
+ SetterMethod->setMethodParams(Context, &Argument, 1);
+ CD->addDecl(SetterMethod);
+ } else
+ // A user declared setter will be synthesize when @synthesize of
+ // the property with the same name is seen in the @implementation
+ SetterMethod->setSynthesized(true);
+ property->setSetterMethodDecl(SetterMethod);
+ }
+ // Add any synthesized methods to the global pool. This allows us to
+ // handle the following, which is supported by GCC (and part of the design).
+ //
+ // @interface Foo
+ // @property double bar;
+ // @end
+ //
+ // void thisIsUnfortunate() {
+ // id foo;
+ // double bar = [foo bar];
+ // }
+ //
+ if (GetterMethod)
+ AddInstanceMethodToGlobalPool(GetterMethod);
+ if (SetterMethod)
+ AddInstanceMethodToGlobalPool(SetterMethod);
+}
+
+void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
+ SourceLocation Loc,
+ unsigned &Attributes) {
+ // FIXME: Improve the reported location.
+
+ // readonly and readwrite/assign/retain/copy conflict.
+ if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
+ ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain))) {
+ const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ?
+ "readwrite" :
+ (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
+ "assign" :
+ (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
+ "copy" : "retain";
+
+ Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
+ diag::err_objc_property_attr_mutually_exclusive :
+ diag::warn_objc_property_attr_mutually_exclusive)
+ << "readonly" << which;
+ }
+
+ // Check for copy or retain on non-object types.
+ if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
+ !PropertyTy->isObjCObjectPointerType() &&
+ !PropertyTy->isBlockPointerType() &&
+ !Context.isObjCNSObjectType(PropertyTy)) {
+ Diag(Loc, diag::err_objc_property_requires_object)
+ << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
+ Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
+ }
+
+ // Check for more than one of { assign, copy, retain }.
+ if (Attributes & ObjCDeclSpec::DQ_PR_assign) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "copy";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "retain";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ }
+ } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "copy" << "retain";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ }
+ }
+
+ // Warn if user supplied no assignment attribute, property is
+ // readwrite, and this is an object type.
+ if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain)) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ PropertyTy->isObjCObjectPointerType()) {
+ // Skip this warning in gc-only mode.
+ if (getLangOptions().getGCMode() != LangOptions::GCOnly)
+ Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
+
+ // If non-gc code warn that this is likely inappropriate.
+ if (getLangOptions().getGCMode() == LangOptions::NonGC)
+ Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+
+ // FIXME: Implement warning dependent on NSCopying being
+ // implemented. See also:
+ // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
+ // (please trim this list while you are at it).
+ }
+
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)
+ && getLangOptions().getGCMode() == LangOptions::GCOnly
+ && PropertyTy->isBlockPointerType())
+ Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
+}
+
+ObjCIvarDecl*
+Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
+ IdentifierInfo *NameII) {
+ ObjCIvarDecl *Ivar = 0;
+ ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII);
+ if (Prop && !Prop->isInvalidDecl()) {
+ DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl);
+ QualType PropType = Context.getCanonicalType(Prop->getType());
+ assert(EnclosingContext &&
+ "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar");
+ Ivar = ObjCIvarDecl::Create(Context, EnclosingContext,
+ Prop->getLocation(),
+ NameII, PropType, /*Dinfo=*/0,
+ ObjCIvarDecl::Public,
+ (Expr *)0);
+ Ivar->setLexicalDeclContext(IDecl);
+ IDecl->addDecl(Ivar);
+ Prop->setPropertyIvarDecl(Ivar);
+ }
+ return Ivar;
+}
+
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index ff59fc3a7d36..f73ec9cb61c5 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1135,6 +1135,12 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// Objective C++: We're able to convert from a pointer to an
// interface to a pointer to a different interface.
if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) {
+ const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType();
+ const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType();
+ if (getLangOptions().CPlusPlus && LHS && RHS &&
+ !ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs(
+ FromObjCPtr->getPointeeType()))
+ return false;
ConvertedType = ToType;
return true;
}
@@ -1405,8 +1411,9 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
}
if (!IgnoreBaseAccess)
- CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true,
- FromClass, ToClass, Paths.front());
+ CheckBaseClassAccess(From->getExprLoc(), FromClass, ToClass,
+ Paths.front(),
+ diag::err_downcast_from_inaccessible_base);
// Must be a base to derived member conversion.
Kind = CastExpr::CK_BaseToDerivedMemberPointer;
@@ -5542,7 +5549,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
- CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess());
+ CheckMemberOperatorAccess(OpLoc, Args[0], 0, Method, Best->getAccess());
if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method))
return ExprError();
@@ -5726,7 +5733,8 @@ 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], Method, Best->getAccess());
+ CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Method,
+ Best->getAccess());
OwningExprResult Arg1
= PerformCopyInitialization(
@@ -5900,7 +5908,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- CheckMemberOperatorAccess(LLoc, Args[0], FnDecl, Best->getAccess());
+ CheckMemberOperatorAccess(LLoc, Args[0], Args[1], FnDecl,
+ Best->getAccess());
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
@@ -6269,7 +6278,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
= cast<CXXConversionDecl>(
Best->Conversions[0].UserDefined.ConversionFunction);
- CheckMemberOperatorAccess(LParenLoc, Object, Conv, Best->getAccess());
+ CheckMemberOperatorAccess(LParenLoc, Object, 0, Conv, Best->getAccess());
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
@@ -6284,7 +6293,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
CommaLocs, RParenLoc).release();
}
- CheckMemberOperatorAccess(LParenLoc, Object,
+ CheckMemberOperatorAccess(LParenLoc, Object, 0,
Best->Function, Best->getAccess());
// We found an overloaded operator(). Build a CXXOperatorCallExpr
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 75d9f67ad9d2..fd65c32c203e 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -76,10 +76,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (!E)
return;
- // Ignore expressions that have void type.
- if (E->getType()->isVoidType())
- return;
-
SourceLocation Loc;
SourceRange R1, R2;
if (!E->isUnusedResultAWarning(Loc, R1, R2, Context))
@@ -103,6 +99,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ if (E->getType()->isVoidType())
+ return;
+
// If the callee has attribute pure, const, or warn_unused_result, warn with
// a more specific message to make it clear what is happening.
if (const Decl *FD = CE->getCalleeDecl()) {
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 7c4cab118366..434d5563e1b3 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Template.h"
@@ -696,6 +697,12 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
RAngleLoc);
}
+static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) {
+ if (SS.isSet())
+ T->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
+ SS.getRange());
+}
+
Sema::DeclResult
Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
@@ -863,6 +870,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
PrevClassTemplate?
PrevClassTemplate->getTemplatedDecl() : 0,
/*DelayTypeCreation=*/true);
+ SetNestedNameSpecifier(NewClass, SS);
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
@@ -3490,6 +3498,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TemplateArgs,
CanonType,
PrevPartial);
+ SetNestedNameSpecifier(Partial, SS);
if (PrevPartial) {
ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial);
@@ -3546,6 +3555,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
ClassTemplate,
Converted,
PrevDecl);
+ SetNestedNameSpecifier(Specialization, SS);
if (PrevDecl) {
ClassTemplate->getSpecializations().RemoveNode(PrevDecl);
@@ -4327,6 +4337,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
TemplateNameLoc,
ClassTemplate,
Converted, PrevDecl);
+ SetNestedNameSpecifier(Specialization, SS);
if (PrevDecl) {
// Remove the previous declaration from the folding set, since we want
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 8f73337e436e..0d6acd0e81c8 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -567,6 +567,15 @@ namespace {
Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
NonTypeTemplateParmDecl *D);
+ /// \brief Transforms a function proto type by performing
+ /// substitution in the function parameters, possibly adjusting
+ /// their types and marking default arguments as uninstantiated.
+ bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
+ llvm::SmallVectorImpl<QualType> &PTypes,
+ llvm::SmallVectorImpl<ParmVarDecl*> &PVars);
+
+ ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm);
+
/// \brief Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
@@ -859,6 +868,61 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
}
+bool
+TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
+ llvm::SmallVectorImpl<QualType> &PTypes,
+ llvm::SmallVectorImpl<ParmVarDecl*> &PVars) {
+ // Create a local instantiation scope for the parameters.
+ Sema::LocalInstantiationScope
+ Scope(SemaRef, SemaRef.CurrentInstantiationScope != 0);
+
+ if (TreeTransform<TemplateInstantiator>::
+ TransformFunctionTypeParams(TL, PTypes, PVars))
+ return true;
+
+ // Check instantiated parameters.
+ if (SemaRef.CheckInstantiatedParams(PVars))
+ return true;
+
+ return false;
+}
+
+ParmVarDecl *
+TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) {
+ TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
+ TypeSourceInfo *NewDI = getDerived().TransformType(OldDI);
+ if (!NewDI)
+ return 0;
+
+ // TODO: do we have to clone this decl if the types match and
+ // there's no default argument?
+
+ ParmVarDecl *NewParm
+ = ParmVarDecl::Create(SemaRef.Context,
+ OldParm->getDeclContext(),
+ OldParm->getLocation(),
+ OldParm->getIdentifier(),
+ NewDI->getType(),
+ NewDI,
+ OldParm->getStorageClass(),
+ /* DefArg */ NULL);
+
+ // Maybe adjust new parameter type.
+ NewParm->setType(SemaRef.adjustParameterType(NewParm->getType()));
+
+ // Mark the (new) default argument as uninstantiated (if any).
+ if (OldParm->hasUninstantiatedDefaultArg()) {
+ Expr *Arg = OldParm->getUninstantiatedDefaultArg();
+ NewParm->setUninstantiatedDefaultArg(Arg);
+ } else if (Expr *Arg = OldParm->getDefaultArg())
+ NewParm->setUninstantiatedDefaultArg(Arg);
+
+ NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
+
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
+ return NewParm;
+}
+
QualType
TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
TemplateTypeParmTypeLoc TL,
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index cf8d38c09583..dbe041c4aade 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Lex/Preprocessor.h"
@@ -89,13 +90,18 @@ namespace {
}
// Helper functions for instantiating methods.
- QualType SubstFunctionType(FunctionDecl *D,
+ TypeSourceInfo *SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
TemplateParameterList *
SubstTemplateParams(TemplateParameterList *List);
+
+ bool SubstQualifier(const DeclaratorDecl *OldDecl,
+ DeclaratorDecl *NewDecl);
+ bool SubstQualifier(const TagDecl *OldDecl,
+ TagDecl *NewDecl);
bool InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate,
@@ -103,6 +109,38 @@ namespace {
};
}
+bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
+ DeclaratorDecl *NewDecl) {
+ NestedNameSpecifier *OldQual = OldDecl->getQualifier();
+ if (!OldQual) return false;
+
+ SourceRange QualRange = OldDecl->getQualifierRange();
+
+ NestedNameSpecifier *NewQual
+ = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs);
+ if (!NewQual)
+ return true;
+
+ NewDecl->setQualifierInfo(NewQual, QualRange);
+ return false;
+}
+
+bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
+ TagDecl *NewDecl) {
+ NestedNameSpecifier *OldQual = OldDecl->getQualifier();
+ if (!OldQual) return false;
+
+ SourceRange QualRange = OldDecl->getQualifierRange();
+
+ NestedNameSpecifier *NewQual
+ = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs);
+ if (!NewQual)
+ return true;
+
+ NewDecl->setQualifierInfo(NewQual, QualRange);
+ return false;
+}
+
// FIXME: Is this too simple?
void TemplateDeclInstantiator::InstantiateAttrs(Decl *Tmpl, Decl *New) {
for (const Attr *TmplAttr = Tmpl->getAttrs(); TmplAttr;
@@ -286,6 +324,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setDeclaredInCondition(D->isDeclaredInCondition());
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(D, Var))
+ return 0;
+
// If we are instantiating a static data member defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
@@ -510,6 +552,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
/*PrevDecl=*/0);
Enum->setInstantiationOfMemberEnum(D);
Enum->setAccess(D->getAccess());
+ if (SubstQualifier(D, Enum)) return 0;
Owner->addDecl(Enum);
Enum->startDefinition();
@@ -610,6 +653,10 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL,
/*DelayTypeCreation=*/true);
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(Pattern, RecordInst))
+ return 0;
+
ClassTemplateDecl *Inst
= ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getIdentifier(), InstParams, RecordInst, 0);
@@ -744,6 +791,11 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
= CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
D->getLocation(), D->getIdentifier(),
D->getTagKeywordLoc(), PrevDecl);
+
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(D, Record))
+ return 0;
+
Record->setImplicit(D->isImplicit());
// FIXME: Check against AS_none is an ugly hack to work around the issue that
// the tag decls introduced by friend class declarations don't have an access
@@ -797,9 +849,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = SubstFunctionType(D, Params);
- if (T.isNull())
+ TypeSourceInfo *TInfo = D->getTypeSourceInfo();
+ TInfo = SubstFunctionType(D, Params);
+ if (!TInfo)
return 0;
+ QualType T = TInfo->getType();
// If we're instantiating a local function declaration, put the result
// in the owner; otherwise we need to find the instantiated context.
@@ -812,9 +866,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
- D->getDeclName(), T, D->getTypeSourceInfo(),
+ D->getDeclName(), T, TInfo,
D->getStorageClass(),
D->isInlineSpecified(), D->hasWrittenPrototype());
+
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(D, Function))
+ return 0;
+
Function->setLexicalDeclContext(Owner);
// Attach the parameters
@@ -932,9 +991,11 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = SubstFunctionType(D, Params);
- if (T.isNull())
+ TypeSourceInfo *TInfo = D->getTypeSourceInfo();
+ TInfo = SubstFunctionType(D, Params);
+ if (!TInfo)
return 0;
+ QualType T = TInfo->getType();
// Build the instantiated method declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
@@ -947,8 +1008,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
SemaRef.Context.getCanonicalType(ClassTy));
Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
Constructor->getLocation(),
- Name, T,
- Constructor->getTypeSourceInfo(),
+ Name, T, TInfo,
Constructor->isExplicit(),
Constructor->isInlineSpecified(), false);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
@@ -966,15 +1026,19 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
ConvTy);
Method = CXXConversionDecl::Create(SemaRef.Context, Record,
Conversion->getLocation(), Name,
- T, Conversion->getTypeSourceInfo(),
+ T, TInfo,
Conversion->isInlineSpecified(),
Conversion->isExplicit());
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
- D->getDeclName(), T, D->getTypeSourceInfo(),
+ D->getDeclName(), T, TInfo,
D->isStatic(), D->isInlineSpecified());
}
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(D, Method))
+ return 0;
+
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
@@ -1504,6 +1568,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
InstTemplateArgs,
CanonType,
0);
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(PartialSpec, InstPartialSpec))
+ return 0;
+
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);
@@ -1514,60 +1582,49 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
return false;
}
-/// \brief Does substitution on the type of the given function, including
-/// all of the function parameters.
-///
-/// \param D The function whose type will be the basis of the substitution
-///
-/// \param Params the instantiated parameter declarations
-
-/// \returns the instantiated function's type if successful, a NULL
-/// type if there was an error.
-QualType
-TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
- llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
- bool InvalidDecl = false;
-
- // Substitute all of the function's formal parameter types.
- TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs);
- llvm::SmallVector<QualType, 4> ParamTys;
- for (FunctionDecl::param_iterator P = D->param_begin(),
- PEnd = D->param_end();
- P != PEnd; ++P) {
- if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) {
- if (PInst->getType()->isVoidType()) {
- SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type);
+bool
+Sema::CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl*> &Params) {
+ bool Invalid = false;
+ for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i)
+ if (ParmVarDecl *PInst = Params[i]) {
+ if (PInst->isInvalidDecl())
+ Invalid = true;
+ else if (PInst->getType()->isVoidType()) {
+ Diag(PInst->getLocation(), diag::err_param_with_void_type);
PInst->setInvalidDecl();
- } else if (SemaRef.RequireNonAbstractType(PInst->getLocation(),
- PInst->getType(),
- diag::err_abstract_type_in_decl,
- Sema::AbstractParamType))
+ Invalid = true;
+ }
+ else if (RequireNonAbstractType(PInst->getLocation(),
+ PInst->getType(),
+ diag::err_abstract_type_in_decl,
+ Sema::AbstractParamType)) {
PInst->setInvalidDecl();
+ Invalid = true;
+ }
+ }
+ return Invalid;
+}
- Params.push_back(PInst);
- ParamTys.push_back(PInst->getType());
+TypeSourceInfo*
+TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
+ llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
+ TypeSourceInfo *OldTInfo = D->getTypeSourceInfo();
+ assert(OldTInfo && "substituting function without type source info");
+ assert(Params.empty() && "parameter vector is non-empty at start");
+ TypeSourceInfo *NewTInfo = SemaRef.SubstType(OldTInfo, TemplateArgs,
+ D->getTypeSpecStartLoc(),
+ D->getDeclName());
+ if (!NewTInfo)
+ return 0;
- if (PInst->isInvalidDecl())
- InvalidDecl = true;
- } else
- InvalidDecl = true;
- }
+ // Get parameters from the new type info.
+ TypeLoc NewTL = NewTInfo->getTypeLoc();
+ FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
+ assert(NewProtoLoc && "Missing prototype?");
+ for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i)
+ Params.push_back(NewProtoLoc->getArg(i));
- // FIXME: Deallocate dead declarations.
- if (InvalidDecl)
- return QualType();
-
- const FunctionProtoType *Proto = D->getType()->getAs<FunctionProtoType>();
- assert(Proto && "Missing prototype?");
- QualType ResultType
- = SemaRef.SubstType(Proto->getResultType(), TemplateArgs,
- D->getLocation(), D->getDeclName());
- if (ResultType.isNull())
- return QualType();
-
- return SemaRef.BuildFunctionType(ResultType, ParamTys.data(), ParamTys.size(),
- Proto->isVariadic(), Proto->getTypeQuals(),
- D->getLocation(), D->getDeclName());
+ return NewTInfo;
}
/// \brief Initializes the common fields of an instantiation function
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 17f94193fed4..d6f3352266aa 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -315,6 +315,21 @@ public:
QualType ObjectType = QualType());
#include "clang/AST/TypeLocNodes.def"
+ /// \brief Transforms the parameters of a function type into the
+ /// given vectors.
+ ///
+ /// The result vectors should be kept in sync; null entries in the
+ /// variables vector are acceptable.
+ ///
+ /// Return true on error.
+ bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
+ llvm::SmallVectorImpl<QualType> &PTypes,
+ llvm::SmallVectorImpl<ParmVarDecl*> &PVars);
+
+ /// \brief Transforms a single function-type parameter. Return null
+ /// on error.
+ ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm);
+
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL,
QualType ObjectType);
@@ -2520,18 +2535,33 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
}
template<typename Derived>
-QualType
-TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
- FunctionProtoTypeLoc TL,
- QualType ObjectType) {
+ParmVarDecl *
+TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) {
+ TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
+ TypeSourceInfo *NewDI = getDerived().TransformType(OldDI);
+ if (!NewDI)
+ return 0;
+
+ if (NewDI == OldDI)
+ return OldParm;
+ else
+ return ParmVarDecl::Create(SemaRef.Context,
+ OldParm->getDeclContext(),
+ OldParm->getLocation(),
+ OldParm->getIdentifier(),
+ NewDI->getType(),
+ NewDI,
+ OldParm->getStorageClass(),
+ /* DefArg */ NULL);
+}
+
+template<typename Derived>
+bool TreeTransform<Derived>::
+ TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
+ llvm::SmallVectorImpl<QualType> &PTypes,
+ llvm::SmallVectorImpl<ParmVarDecl*> &PVars) {
FunctionProtoType *T = TL.getTypePtr();
- QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
- if (ResultType.isNull())
- return QualType();
- // Transform the parameters.
- llvm::SmallVector<QualType, 4> ParamTypes;
- llvm::SmallVector<ParmVarDecl*, 4> ParamDecls;
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
ParmVarDecl *OldParm = TL.getArg(i);
@@ -2539,24 +2569,9 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
ParmVarDecl *NewParm;
if (OldParm) {
- TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
- assert(OldDI->getType() == T->getArgType(i));
-
- TypeSourceInfo *NewDI = getDerived().TransformType(OldDI);
- if (!NewDI)
- return QualType();
-
- if (NewDI == OldDI)
- NewParm = OldParm;
- else
- NewParm = ParmVarDecl::Create(SemaRef.Context,
- OldParm->getDeclContext(),
- OldParm->getLocation(),
- OldParm->getIdentifier(),
- NewDI->getType(),
- NewDI,
- OldParm->getStorageClass(),
- /* DefArg */ NULL);
+ NewParm = getDerived().TransformFunctionTypeParam(OldParm);
+ if (!NewParm)
+ return true;
NewType = NewParm->getType();
// Deal with the possibility that we don't have a parameter
@@ -2567,13 +2582,32 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
QualType OldType = T->getArgType(i);
NewType = getDerived().TransformType(OldType);
if (NewType.isNull())
- return QualType();
+ return true;
}
- ParamTypes.push_back(NewType);
- ParamDecls.push_back(NewParm);
+ PTypes.push_back(NewType);
+ PVars.push_back(NewParm);
}
+ return false;
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
+ FunctionProtoTypeLoc TL,
+ QualType ObjectType) {
+ FunctionProtoType *T = TL.getTypePtr();
+ QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
+ if (ResultType.isNull())
+ return QualType();
+
+ // Transform the parameters.
+ llvm::SmallVector<QualType, 4> ParamTypes;
+ llvm::SmallVector<ParmVarDecl*, 4> ParamDecls;
+ if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls))
+ return QualType();
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
ResultType != T->getResultType() ||
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index a06fb2e3e3c2..83b4227aa3bc 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
// C++'0x [class.friend] p1:
// A friend of a class is a function or class that is given permission to use
@@ -60,3 +60,58 @@ namespace N {
x.g2(); // expected-error{{no member named 'g2' in 'N::X'}}
}
}
+
+namespace test0 {
+ class ClassFriend {
+ void test();
+ };
+
+ class MemberFriend {
+ void test();
+ };
+
+ void declared_test();
+
+ class Class {
+ static void member(); // expected-note 2 {{declared private here}}
+
+ friend class ClassFriend;
+ friend class UndeclaredClassFriend;
+
+ friend void undeclared_test();
+ friend void declared_test();
+ friend void MemberFriend::test();
+ };
+
+ void declared_test() {
+ Class::member();
+ }
+
+ void undeclared_test() {
+ Class::member();
+ }
+
+ void unfriended_test() {
+ Class::member(); // expected-error {{'member' is a private member of 'test0::Class'}}
+ }
+
+ void ClassFriend::test() {
+ Class::member();
+ }
+
+ void MemberFriend::test() {
+ Class::member();
+ }
+
+ class UndeclaredClassFriend {
+ void test() {
+ Class::member();
+ }
+ };
+
+ class ClassNonFriend {
+ void test() {
+ Class::member(); // expected-error {{'member' is a private member of 'test0::Class'}}
+ }
+ };
+}
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 7aa614cd8b1a..15b336a4d8e6 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -99,16 +99,124 @@ namespace test2 {
// Implicit destructor calls.
namespace test3 {
- class A{
+ class A {
private:
~A(); // expected-note 3 {{declared private here}}
static A foo;
};
- A a; // expected-error {{'~A' is a private member}}
+ A a; // expected-error {{variable of type 'test3::A' has private destructor}}
A A::foo;
- void foo(A param) { // expected-error {{'~A' is a private member}}
- A local; // expected-error {{'~A' is a private member}}
+ void foo(A param) { // expected-error {{variable of type 'test3::A' has private destructor}}
+ 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(); };
+
+ // These don't cause diagnostics because we don't need the destructor.
+ class Derived0 : Base<0> { ~Derived0(); };
+ class Derived1 : Base<1> { };
+
+ class Derived2 : // 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}}
+ virtual Base3
+ {
+ ~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}}
+ virtual Base3
+ {};
+ Derived3 d3;
+}
+
+// Conversion functions.
+namespace test4 {
+ class Base {
+ private:
+ operator Private(); // expected-note 4 {{declared private here}}
+ public:
+ operator Public();
+ };
+
+ class Derived1 : private Base { // expected-note 2 {{declared private here}} \
+ // expected-note {{constrained by private inheritance}}
+ Private test1() { return *this; } // expected-error {{'operator Private' is a private member}}
+ Public test2() { return *this; }
+ };
+ Private test1(Derived1 &d) { return d; } // expected-error {{'operator Private' is a private member}} \
+ // expected-error {{cannot cast 'test4::Derived1' to its private base class}}
+ Public test2(Derived1 &d) { return d; } // expected-error {{cannot cast 'test4::Derived1' to its private base class}} \
+ // expected-error {{'operator Public' is a private member}}
+
+
+ class Derived2 : public Base {
+ Private test1() { return *this; } // expected-error {{'operator Private' is a private member}}
+ Public test2() { return *this; }
+ };
+ Private test1(Derived2 &d) { return d; } // expected-error {{'operator Private' is a private member}}
+ Public test2(Derived2 &d) { return d; }
+
+ class Derived3 : private Base { // expected-note {{constrained by private inheritance here}} \
+ // expected-note {{declared private here}}
+ public:
+ operator Private();
+ };
+ Private test1(Derived3 &d) { return d; }
+ Public test2(Derived3 &d) { return d; } // expected-error {{'operator Public' is a private member of 'test4::Base'}} \
+ // expected-error {{cannot cast 'test4::Derived3' to its private base class}}
+
+ class Derived4 : public Base {
+ public:
+ operator Private();
+ };
+ Private test1(Derived4 &d) { return d; }
+ Public test2(Derived4 &d) { return d; }
+}
+
+// Implicit copy assignment operator uses.
+namespace test5 {
+ class A {
+ void operator=(const A &); // expected-note 2 {{declared private here}}
+ };
+
+ class Test1 { A a; }; // expected-error {{field of type 'test5::A' has private copy assignment operator}}
+ void test1() {
+ Test1 a;
+ a = Test1();
+ }
+
+ class Test2 : A {}; // expected-error {{base class 'test5::A' has private copy assignment operator}}
+ void test2() {
+ Test2 a;
+ a = Test2();
+ }
+}
+
+// Implicit copy constructor uses.
+namespace test6 {
+ class A {
+ public: A();
+ private: A(const A &); // expected-note 2 {{declared private here}}
+ };
+
+ class Test1 { A a; }; // expected-error {{field of type 'test6::A' has private copy constructor}}
+ void test1(const Test1 &t) {
+ Test1 a = t;
+ }
+
+ class Test2 : A {}; // expected-error {{base class 'test6::A' has private copy constructor}}
+ void test2(const Test2 &t) {
+ Test2 a = t;
}
}
diff --git a/test/CXX/temp/temp.res/temp.local/p7.cpp b/test/CXX/temp/temp.res/temp.local/p7.cpp
new file mode 100644
index 000000000000..bd05e756a19e
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.local/p7.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<class T> struct A {
+ int B;
+ int f();
+};
+
+template<class B> int A<B>::f() {
+ return B;
+}
diff --git a/test/CXX/temp/temp.res/temp.local/p8.cpp b/test/CXX/temp/temp.res/temp.local/p8.cpp
new file mode 100644
index 000000000000..5d9d50913f36
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.local/p8.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace N {
+ enum { C };
+ template<class T> class B {
+ void f(T);
+ };
+}
+
+template<class C> void N::B<C>::f(C) {
+ C b;
+}
+
+namespace N {
+ enum { D };
+ namespace M {
+ enum { C , D };
+ template<typename C> class X {
+ template<typename U> void f(C, U);
+
+ template<typename D> void g(C, D) {
+ C c;
+ D d;
+ }
+ };
+
+ struct Y {
+ template<typename U> void f(U);
+ };
+ }
+
+ struct Y {
+ template<typename D> void f(D);
+ };
+}
+
+template<typename C>
+template<typename D>
+void N::M::X<C>::f(C, D) {
+ C c;
+ D d;
+}
+
+template<typename C>
+void N::M::Y::f(C) {
+ C c;
+}
+
+template<typename D>
+void N::Y::f(D) {
+ D d;
+}
+
diff --git a/test/CXX/temp/temp.res/temp.local/p9.cpp b/test/CXX/temp/temp.res/temp.local/p9.cpp
new file mode 100644
index 000000000000..9ca8d8877d7d
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.local/p9.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct A {
+ struct B { void f(); };
+ int a;
+ int Y;
+};
+
+template<class B, class a> struct X : A {
+ B b; // A's B
+ a c; // expected-error{{unknown type name 'a'}}
+
+ void g() {
+ b.g(); // expected-error{{no member named 'g' in 'A::B'}}
+ }
+};
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp
index 70eb69641867..d8f7b52145dd 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp
@@ -12,10 +12,10 @@ T X<T>::member1;
template<typename T>
T X<T>::member2 = 17;
-// CHECK: @_ZN1XIiE7member1E = global i32 0
+// CHECK: @_ZN1XIiE7member1E = weak global i32 0
template int X<int>::member1;
-// CHECK: @_ZN1XIiE7member2E = global i32 17
+// CHECK: @_ZN1XIiE7member2E = weak global i32 17
template int X<int>::member2;
// For implicit instantiation of
diff --git a/test/CodeGen/varargs.c b/test/CodeGen/varargs.c
new file mode 100644
index 000000000000..b3dba240b559
--- /dev/null
+++ b/test/CodeGen/varargs.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s
+
+
+// PR6433 - Don't crash on va_arg(typedef).
+typedef double gdouble;
+void focus_changed_cb () {
+ __builtin_va_list pa;
+ double mfloat;
+ mfloat = __builtin_va_arg((pa), gdouble);
+}
+
diff --git a/test/CodeGenCXX/PR6474.cpp b/test/CodeGenCXX/PR6474.cpp
index 68c09c9b95d5..0b155cef8355 100644
--- a/test/CodeGenCXX/PR6474.cpp
+++ b/test/CodeGenCXX/PR6474.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm
+// RUN: %clang_cc1 %s -emit-llvm-only
namespace test0 {
template <typename T> struct X {
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
index ab9174e8f406..24d1a6739229 100644
--- a/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o %t %s
-// RUN: grep "define i32 @_ZNK4plusIillEclERKiRKl" %t | count 1
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s
template<typename T, typename U, typename Result>
struct plus {
@@ -11,4 +10,5 @@ Result plus<T, U, Result>::operator()(const T& t, const U& u) const {
return t + u;
}
+// CHECK: define weak_odr i32 @_ZNK4plusIillEclERKiRKl
template struct plus<int, long, long>;
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
index cdad39852c9f..6f1ca5568ed6 100644
--- a/test/CodeGenCXX/mangle-exprs.cpp
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -30,15 +30,15 @@ namespace Casts {
template <int N> T<N> f() { return T<N>(); }
- // CHECK: define void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE
+ // CHECK: define weak_odr void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE
template void implicit<4>(void*);
- // CHECK: define void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ // CHECK: define weak_odr void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
template void cstyle<4>(void*);
- // CHECK: define void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ // CHECK: define weak_odr void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
template void functional<4>(void*);
- // CHECK: define void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ // CHECK: define weak_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
template void static_<4>(void*);
- // CHECK: define i64 @_ZN5Casts1fILi6EEENS_1TIXT_EEEv
+ // CHECK: define weak_odr i64 @_ZN5Casts1fILi6EEENS_1TIXT_EEEv
template T<6> f<6>();
}
diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp
index 57f30a762ed0..22949da64ad8 100644
--- a/test/CodeGenCXX/mangle-template.cpp
+++ b/test/CodeGenCXX/mangle-template.cpp
@@ -82,7 +82,7 @@ namespace test7 {
X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { }
};
- // CHECK: define void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE
+ // CHECK: define weak_odr void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE
template X<int>::X(double*, float*);
}
@@ -101,6 +101,6 @@ namespace test8 {
template<typename T>
void f(int_c<meta<T>::type::value>) { }
- // CHECK: define void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE
+ // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE
template void f<int>(int_c<sizeof(int)>);
}
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index e18ca03d1be2..8dee41beb482 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -250,26 +250,26 @@ void f() { __fill_a<int>(); }
namespace Expressions {
// Unary operators.
-// CHECK: define void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i
+// CHECK: define weak_odr void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i
template <int i> void f1(int (*)[(-i) + 2]) { };
template void f1<1>(int (*)[1]);
-// CHECK: define void @_ZN11Expressions2f2ILi1EEEvPApsT__i
+// CHECK: define weak_odr void @_ZN11Expressions2f2ILi1EEEvPApsT__i
template <int i> void f2(int (*)[+i]) { };
template void f2<1>(int (*)[1]);
// Binary operators.
-// CHECK: define void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i
+// CHECK: define weak_odr void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i
template <int i> void f3(int (*)[i+i]) { };
template void f3<1>(int (*)[2]);
-// CHECK: define void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i
+// CHECK: define weak_odr void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i
template <int i> void f4(int (*)[2 + i+i]) { };
template void f4<1>(int (*)[4]);
// The ternary operator.
-// CHECK: define void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i
+// CHECK: define weak_odr void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i
template <bool b> void f4(int (*)[b ? 1 : 2]) { };
template void f4<true>(int (*)[1]);
}
@@ -305,7 +305,7 @@ template<typename T, typename = Policy<P, true> > class Alloc
T *allocate(int, const void*) { return 0; }
};
-// CHECK: define i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv
+// CHECK: define weak_odr i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv
template class Alloc<char>;
}
@@ -369,7 +369,7 @@ namespace test0 {
namespace test1 {
template<typename T> struct X { };
template<template<class> class Y, typename T> void f(Y<T>) { }
- // CHECK: define void @_ZN5test11fINS_1XEiEEvT_IT0_E
+ // CHECK: define weak_odr void @_ZN5test11fINS_1XEiEEvT_IT0_E
template void f(X<int>);
}
@@ -399,10 +399,10 @@ namespace test3 {
//template <class T> decltype(((T*) 0)->Path1::ab) get_ab_1(T &ref) { return ref.Path1::ab; }
//template <class T> decltype(((T*) 0)->Path2::ab) get_ab_2(T &ref) { return ref.Path2::ab; }
- // define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path11pERS2_(
+ // define weak_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path11pERS2_(
template <class T> decltype(((T*) 0)->Path1::p) get_p_1(T &ref) { return ref.Path1::p; }
- // define linkonce_odr double @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path21pERS2_(
+ // define weak_odr double @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path21pERS2_(
template <class T> decltype(((T*) 0)->Path2::p) get_p_2(T &ref) { return ref.Path2::p; }
Derived obj;
@@ -414,3 +414,42 @@ namespace test3 {
get_p_2(obj);
}
}
+
+// CHECK: define void @_ZN5test41gEPNS_3zedIXadL_ZNS_3foo3barEEEEE
+namespace test4 {
+ struct foo { int bar; };
+ template <int (foo::*)>
+ struct zed {};
+ void g(zed<&foo::bar>*)
+ {}
+}
+// CHECK: define void @_ZN5test51gEPNS_3zedIXadL_ZNS_3foo3barEEEEE
+namespace test5 {
+ struct foo { static int bar; };
+ template <int *>
+ struct zed {};
+ void g(zed<&foo::bar>*)
+ {}
+}
+// CHECK: define void @_ZN5test61gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE
+namespace test6 {
+ struct foo { int bar(); };
+ template <int (foo::*)()>
+ struct zed {};
+ void g(zed<&foo::bar>*)
+ {}
+}
+// CHECK: define void @_ZN5test71gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE
+namespace test7 {
+ struct foo { static int bar(); };
+ template <int (*f)()>
+ struct zed {};
+ void g(zed<&foo::bar>*)
+ {}
+}
+// CHECK: define weak_odr void @_ZN5test81AILZNS_1B5valueEEE3incEv
+namespace test8 {
+ template <int &counter> class A { void inc() { counter++; } };
+ class B { static int value; };
+ template class A<B::value>;
+}
diff --git a/test/CodeGenCXX/member-templates.cpp b/test/CodeGenCXX/member-templates.cpp
index 355ba20e171f..bcf1187e623f 100644
--- a/test/CodeGenCXX/member-templates.cpp
+++ b/test/CodeGenCXX/member-templates.cpp
@@ -15,8 +15,8 @@ struct B {
template<typename T> B::B(T) {}
-// CHECK: define void @_ZN1BC1IiEET_(%struct.B* %this, i32)
-// CHECK: define void @_ZN1BC2IiEET_(%struct.B* %this, i32)
+// CHECK: define weak_odr void @_ZN1BC1IiEET_(%struct.B* %this, i32)
+// CHECK: define weak_odr void @_ZN1BC2IiEET_(%struct.B* %this, i32)
template B::B(int);
template<typename T>
diff --git a/test/CodeGenCXX/template-linkage.cpp b/test/CodeGenCXX/template-linkage.cpp
index 5d573d6e829b..ccd61a7bbe30 100644
--- a/test/CodeGenCXX/template-linkage.cpp
+++ b/test/CodeGenCXX/template-linkage.cpp
@@ -6,19 +6,19 @@ template<typename T> struct A {
// Explicit instantiations have external linkage.
-// CHECK: define void @_ZN1AIiE1gEv(
+// CHECK: define weak_odr void @_ZN1AIiE1gEv(
template void A<int>::g();
-// CHECK: define void @_ZN1AIfE1fEf(
-// CHECK: define void @_ZN1AIfE1gEv(
+// CHECK: define weak_odr void @_ZN1AIfE1fEf(
+// CHECK: define weak_odr void @_ZN1AIfE1gEv(
// FIXME: This should also emit the vtable.
template struct A<float>;
-// CHECK: define void @_Z1fIiEvT_
+// CHECK: define weak_odr void @_Z1fIiEvT_
template <typename T> void f(T) { }
template void f<int>(int);
-// CHECK: define void @_Z1gIiEvT_
+// CHECK: define weak_odr void @_Z1gIiEvT_
template <typename T> inline void g(T) { }
template void g<int>(int);
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index 3b624afd0ad1..cd0cf77f53b2 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -256,7 +256,7 @@ namespace PR6199 {
struct B { operator A(); };
- // CHECK: define void @_ZN6PR61992f2IiEENS_1AET_
+ // CHECK: define weak_odr void @_ZN6PR61992f2IiEENS_1AET_
template<typename T> A f2(T) {
B b;
// CHECK: call void @_ZN6PR61991BcvNS_1AEEv
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index 5c783f1f23dc..f11ae345cc7b 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -698,6 +698,65 @@ struct C : A, B {
// CHECK-NEXT: 22 | void Test18::D::f()
// CHECK-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset]
// CHECK-NEXT: 23 | [unused] void Test18::C::g()
+
+// CHECK: Construction vtable for ('Test18::B', 0) in 'Test18::D' (7 entries).
+// CHECK-NEXT: 0 | vbase_offset (0)
+// CHECK-NEXT: 1 | vcall_offset (0)
+// CHECK-NEXT: 2 | vcall_offset (0)
+// CHECK-NEXT: 3 | offset_to_top (0)
+// CHECK-NEXT: 4 | Test18::B RTTI
+// CHECK-NEXT: -- (Test18::A, 0) vtable address --
+// CHECK-NEXT: -- (Test18::B, 0) vtable address --
+// CHECK-NEXT: 5 | void Test18::B::f()
+// CHECK-NEXT: 6 | void Test18::A::g()
+
+// CHECK: Construction vtable for ('Test18::C', 8) in 'Test18::D' (20 entries).
+// CHECK-NEXT: 0 | vcall_offset (0)
+// CHECK-NEXT: 1 | vcall_offset (0)
+// CHECK-NEXT: 2 | vbase_offset (-8)
+// CHECK-NEXT: 3 | offset_to_top (0)
+// CHECK-NEXT: 4 | Test18::C RTTI
+// CHECK-NEXT: -- (Test18::A, 8) vtable address --
+// CHECK-NEXT: -- (Test18::C, 8) vtable address --
+// CHECK-NEXT: 5 | void Test18::A::f()
+// CHECK-NEXT: 6 | void Test18::C::g()
+// CHECK-NEXT: 7 | vbase_offset (-16)
+// CHECK-NEXT: 8 | vcall_offset (-8)
+// CHECK-NEXT: 9 | vcall_offset (0)
+// CHECK-NEXT: 10 | offset_to_top (-8)
+// CHECK-NEXT: 11 | Test18::C RTTI
+// CHECK-NEXT: -- (Test18::A, 16) vtable address --
+// CHECK-NEXT: -- (Test18::B, 16) vtable address --
+// CHECK-NEXT: 12 | void Test18::B::f()
+// CHECK-NEXT: 13 | [unused] void Test18::C::g()
+// CHECK-NEXT: 14 | vcall_offset (8)
+// CHECK-NEXT: 15 | vcall_offset (16)
+// CHECK-NEXT: 16 | offset_to_top (8)
+// CHECK-NEXT: 17 | Test18::C RTTI
+// CHECK-NEXT: -- (Test18::A, 0) vtable address --
+// CHECK-NEXT: 18 | void Test18::B::f()
+// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-NEXT: 19 | void Test18::C::g()
+// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+
+// CHECK: Construction vtable for ('Test18::B', 16) in 'Test18::D' (13 entries).
+// CHECK-NEXT: 0 | vbase_offset (-16)
+// CHECK-NEXT: 1 | vcall_offset (-16)
+// CHECK-NEXT: 2 | vcall_offset (0)
+// CHECK-NEXT: 3 | offset_to_top (0)
+// CHECK-NEXT: 4 | Test18::B RTTI
+// CHECK-NEXT: -- (Test18::A, 16) vtable address --
+// CHECK-NEXT: -- (Test18::B, 16) vtable address --
+// CHECK-NEXT: 5 | void Test18::B::f()
+// CHECK-NEXT: 6 | [unused] void Test18::A::g()
+// CHECK-NEXT: 7 | vcall_offset (0)
+// CHECK-NEXT: 8 | vcall_offset (16)
+// CHECK-NEXT: 9 | offset_to_top (16)
+// CHECK-NEXT: 10 | Test18::B RTTI
+// CHECK-NEXT: -- (Test18::A, 0) vtable address --
+// CHECK-NEXT: 11 | void Test18::B::f()
+// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-NEXT: 12 | void Test18::A::g()
struct D : virtual B, virtual C, virtual A
{
virtual void f();
@@ -827,6 +886,13 @@ class E : virtual C { };
// CHECK-NEXT: -- (Test21::C, 8) vtable address --
// 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-NEXT: Test21::B | -40
+// CHECK-NEXT: Test21::C | -48
+// CHECK-NEXT: Test21::D | -56
+// CHECK-NEXT: Test21::E | -64
class F : virtual D, virtual E {
virtual void f();
};
@@ -1091,3 +1157,130 @@ class D : virtual B, virtual C {
void D::d() { }
}
+
+namespace Test27 {
+
+// Test that we don't generate a secondary vtable for C in the D-in-E vtable, since
+// C doesn't have any virtual bases.
+
+struct A {
+ virtual void a();
+};
+
+struct B {
+ virtual void b();
+};
+
+struct C {
+ virtual void c();
+};
+
+struct D : A, virtual B, C {
+ virtual void d();
+};
+
+// CHECK: Vtable for 'Test27::E' (13 entries).
+// CHECK-NEXT: 0 | vbase_offset (16)
+// CHECK-NEXT: 1 | offset_to_top (0)
+// CHECK-NEXT: 2 | Test27::E RTTI
+// CHECK-NEXT: -- (Test27::A, 0) vtable address --
+// CHECK-NEXT: -- (Test27::D, 0) vtable address --
+// CHECK-NEXT: -- (Test27::E, 0) vtable address --
+// CHECK-NEXT: 3 | void Test27::A::a()
+// CHECK-NEXT: 4 | void Test27::D::d()
+// CHECK-NEXT: 5 | void Test27::E::e()
+// CHECK-NEXT: 6 | offset_to_top (-8)
+// CHECK-NEXT: 7 | Test27::E RTTI
+// CHECK-NEXT: -- (Test27::C, 8) vtable address --
+// CHECK-NEXT: 8 | void Test27::C::c()
+// CHECK-NEXT: 9 | vcall_offset (0)
+// CHECK-NEXT: 10 | offset_to_top (-16)
+// CHECK-NEXT: 11 | Test27::E RTTI
+// CHECK-NEXT: -- (Test27::B, 16) vtable address --
+// CHECK-NEXT: 12 | void Test27::B::b()
+
+// CHECK: Construction vtable for ('Test27::D', 0) in 'Test27::E' (9 entries).
+// CHECK-NEXT: 0 | vbase_offset (16)
+// CHECK-NEXT: 1 | offset_to_top (0)
+// CHECK-NEXT: 2 | Test27::D RTTI
+// CHECK-NEXT: -- (Test27::A, 0) vtable address --
+// CHECK-NEXT: -- (Test27::D, 0) vtable address --
+// CHECK-NEXT: 3 | void Test27::A::a()
+// CHECK-NEXT: 4 | void Test27::D::d()
+// CHECK-NEXT: 5 | vcall_offset (0)
+// CHECK-NEXT: 6 | offset_to_top (-16)
+// CHECK-NEXT: 7 | Test27::D RTTI
+// CHECK-NEXT: -- (Test27::B, 16) vtable address --
+// CHECK-NEXT: 8 | void Test27::B::b()
+struct E : D {
+ virtual void e();
+};
+void E::e() { }
+
+}
+
+namespace Test28 {
+
+// Check that we do include the vtable for B in the D-in-E construction vtable, since
+// B is a base class of a virtual base (C).
+
+struct A {
+ virtual void a();
+};
+
+struct B {
+ virtual void b();
+};
+
+struct C : A, B {
+ virtual void c();
+};
+
+struct D : virtual C {
+};
+
+// CHECK: Vtable for 'Test28::E' (14 entries).
+// CHECK-NEXT: 0 | vbase_offset (8)
+// CHECK-NEXT: 1 | offset_to_top (0)
+// CHECK-NEXT: 2 | Test28::E RTTI
+// CHECK-NEXT: -- (Test28::D, 0) vtable address --
+// CHECK-NEXT: -- (Test28::E, 0) vtable address --
+// CHECK-NEXT: 3 | void Test28::E::e()
+// CHECK-NEXT: 4 | vcall_offset (8)
+// CHECK-NEXT: 5 | vcall_offset (0)
+// CHECK-NEXT: 6 | vcall_offset (0)
+// CHECK-NEXT: 7 | offset_to_top (-8)
+// CHECK-NEXT: 8 | Test28::E RTTI
+// CHECK-NEXT: -- (Test28::A, 8) vtable address --
+// CHECK-NEXT: -- (Test28::C, 8) vtable address --
+// CHECK-NEXT: 9 | void Test28::A::a()
+// CHECK-NEXT: 10 | void Test28::C::c()
+// CHECK-NEXT: 11 | offset_to_top (-16)
+// CHECK-NEXT: 12 | Test28::E RTTI
+// CHECK-NEXT: -- (Test28::B, 16) vtable address --
+// CHECK-NEXT: 13 | void Test28::B::b()
+
+// CHECK: Construction vtable for ('Test28::D', 0) in 'Test28::E' (13 entries).
+// CHECK-NEXT: 0 | vbase_offset (8)
+// CHECK-NEXT: 1 | offset_to_top (0)
+// CHECK-NEXT: 2 | Test28::D RTTI
+// CHECK-NEXT: -- (Test28::D, 0) vtable address --
+// CHECK-NEXT: 3 | vcall_offset (8)
+// CHECK-NEXT: 4 | vcall_offset (0)
+// CHECK-NEXT: 5 | vcall_offset (0)
+// CHECK-NEXT: 6 | offset_to_top (-8)
+// CHECK-NEXT: 7 | Test28::D RTTI
+// CHECK-NEXT: -- (Test28::A, 8) vtable address --
+// CHECK-NEXT: -- (Test28::C, 8) vtable address --
+// CHECK-NEXT: 8 | void Test28::A::a()
+// CHECK-NEXT: 9 | void Test28::C::c()
+// CHECK-NEXT: 10 | offset_to_top (-16)
+// CHECK-NEXT: 11 | Test28::D RTTI
+// CHECK-NEXT: -- (Test28::B, 16) vtable address --
+// CHECK-NEXT: 12 | void Test28::B::b()
+struct E : D {
+ virtual void e();
+};
+void E::e() { }
+
+}
diff --git a/test/PCH/changed-files.c b/test/PCH/changed-files.c
new file mode 100644
index 000000000000..36453c48e716
--- /dev/null
+++ b/test/PCH/changed-files.c
@@ -0,0 +1,11 @@
+const char *s0 = 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"
+
+// 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"
diff --git a/test/Parser/missing-end.m b/test/Parser/missing-end.m
new file mode 100644
index 000000000000..fb264610aecb
--- /dev/null
+++ b/test/Parser/missing-end.m
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface AAA
+{
+}
+@ x// expected-error{{expected an Objective-C directive after '@'}}
+// expected-error{{missing @end}}
diff --git a/test/Rewriter/rewrite-local-externs-in-block.mm b/test/Rewriter/rewrite-local-externs-in-block.mm
new file mode 100644
index 000000000000..d1a56a89ee58
--- /dev/null
+++ b/test/Rewriter/rewrite-local-externs-in-block.mm
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// radar 7735987
+
+extern "C" int printf(const char*, ...);
+
+void bar(void (^block)()) {
+ block();
+}
+
+int main() {
+ static int myArr[3] = {1, 2, 3};
+ printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]);
+
+ bar(^{
+ printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]);
+ myArr[0] = 42;
+ myArr[2] = 100;
+ printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]);
+ });
+
+ printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]);
+}
diff --git a/test/Rewriter/rewrite-super-message.mm b/test/Rewriter/rewrite-super-message.mm
new file mode 100644
index 000000000000..036aa1bb3186
--- /dev/null
+++ b/test/Rewriter/rewrite-super-message.mm
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=struct objc_object *" -D"Class=struct objc_class *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o - %t-rw.cpp | FileCheck %t-rw.cpp
+// radar 7738453
+
+void *sel_registerName(const char *);
+
+@interface __NSCFType
+@end
+
+@interface __NSCFString : __NSCFType
+- (const char *)UTF8String;
+@end
+
+@implementation __NSCFString
+- (const char *)UTF8String {
+ return (const char *)[super UTF8String];
+}
+@end
+
+// CHECK: call %struct.objc_class* @class_getSuperclass
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 2821a935c3c7..7c8c36f0c145 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -274,3 +274,11 @@ void test4() {
if (value < (unsigned long) &ptr4) // expected-warning {{comparison of integers of different signs}}
return;
}
+
+// PR4807
+int test5(unsigned int x) {
+ return (x < 0) // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ && (0 > x) // expected-warning {{comparison of 0 > unsigned expression is always false}}
+ && (x >= 0) // expected-warning {{comparison of unsigned expression >= 0 is always true}}
+ && (0 <= x); // expected-warning {{comparison of 0 <= unsigned expression is always true}}
+}
diff --git a/test/Sema/missing-field-initializers.c b/test/Sema/missing-field-initializers.c
new file mode 100644
index 000000000000..828191462444
--- /dev/null
+++ b/test/Sema/missing-field-initializers.c
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wmissing-field-initializers %s
+
+// This was PR4808.
+
+struct Foo { int a, b; };
+
+struct Foo foo0 = { 1 }; // expected-warning {{missing field 'b' initializer}}
+struct Foo foo1 = { .a = 1 }; // designator avoids MFI warning
+struct Foo foo2 = { .b = 1 }; // designator avoids MFI warning
+
+struct Foo bar0[] = {
+ { 1,2 },
+ { 1 }, // expected-warning {{missing field 'b' initializer}}
+ { 1,2 }
+};
+
+struct Foo bar1[] = {
+ 1, 2,
+ 1, 2,
+ 1
+}; // expected-warning {{missing field 'b' initializer}}
+
+struct One { int a; int b; };
+struct Two { float c; float d; float e; };
+
+struct Three {
+ union {
+ struct One one;
+ struct Two two;
+ } both;
+};
+
+struct Three t0 = {
+ { .one = { 1, 2 } }
+};
+struct Three t1 = {
+ { .two = { 1.0f, 2.0f, 3.0f } }
+};
+
+struct Three data[] = {
+ { { .one = { 1, 2 } } },
+ { { .one = { 1 } } }, // expected-warning {{missing field 'b' initializer}}
+ { { .two = { 1.0f, 2.0f, 3.0f } } },
+ { { .two = { 1.0f, 2.0f } } } // expected-warning {{missing field 'e' initializer}}
+};
+
+struct { int:5; int a; int:5; int b; int:5 } noNamedImplicit[] = {
+ { 1, 2 },
+ { 1 } // expected-warning {{missing field 'b' initializer}}
+};
diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c
index ff631ed9c85e..28c3e4cf8c90 100644
--- a/test/Sema/overloadable.c
+++ b/test/Sema/overloadable.c
@@ -50,4 +50,13 @@ void test_promote(short* sp) {
promote(sp); // expected-error{{call to unavailable function 'promote'}}
}
-
+// PR6600
+typedef double Double;
+typedef Double DoubleVec __attribute__((vector_size(16)));
+typedef int Int;
+typedef Int IntVec __attribute__((vector_size(16)));
+double magnitude(DoubleVec) __attribute__((__overloadable__));
+double magnitude(IntVec) __attribute__((__overloadable__));
+double test_p6600(DoubleVec d) {
+ return magnitude(d) * magnitude(d);
+}
diff --git a/test/Sema/return.c b/test/Sema/return.c
index 5d1c97f2a2ef..3ab23f4f8f8e 100644
--- a/test/Sema/return.c
+++ b/test/Sema/return.c
@@ -1,4 +1,4 @@
-// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wno-unreachable-code
+// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wno-unreachable-code -Wno-unused-value
// clang emits the following warning by default.
// With GCC, -pedantic, -Wreturn-type or -Wall are required to produce the
diff --git a/test/Sema/warn-unused-value.c b/test/Sema/warn-unused-value.c
new file mode 100644
index 000000000000..2e0fa54effbf
--- /dev/null
+++ b/test/Sema/warn-unused-value.c
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value %s
+
+int i = 0;
+int j = 0;
+
+void foo();
+
+// PR4806
+void pr4806() {
+ 1,foo(); // expected-warning {{expression result unused}}
+
+ // other
+ foo();
+ i; // expected-warning {{expression result unused}}
+
+ i,foo(); // expected-warning {{expression result unused}}
+ foo(),i; // expected-warning {{expression result unused}}
+
+ i,j,foo(); // expected-warning {{expression result unused}}
+ i,foo(),j; // expected-warning {{expression result unused}}
+ foo(),i,j; // expected-warning {{expression result unused}}
+
+ i++;
+
+ i++,foo();
+ foo(),i++;
+
+ i++,j,foo(); // expected-warning {{expression result unused}}
+ i++,foo(),j; // expected-warning {{expression result unused}}
+ foo(),i++,j; // expected-warning {{expression result unused}}
+
+ i,j++,foo(); // expected-warning {{expression result unused}}
+ i,foo(),j++; // expected-warning {{expression result unused}}
+ foo(),i,j++; // expected-warning {{expression result unused}}
+
+ i++,j++,foo();
+ i++,foo(),j++;
+ foo(),i++,j++;
+
+ {};
+ ({});
+ ({}),foo();
+ foo(),({});
+
+ (int)1U; // expected-warning {{expression result unused}}
+ (void)1U;
+
+ // pointer to volatile has side effect (thus no warning)
+ int* pi = &i;
+ volatile int* pj = &j;
+ *pi; // expected-warning {{expression result unused}}
+ *pj;
+}
diff --git a/test/Sema/warn-write-strings.c b/test/Sema/warn-write-strings.c
new file mode 100644
index 000000000000..938f0be7721f
--- /dev/null
+++ b/test/Sema/warn-write-strings.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s
+
+// PR4804
+char* x = "foo"; // expected-warning {{initializing 'char const [4]' discards qualifiers, expected 'char *'}}
diff --git a/test/SemaCXX/PR6562.cpp b/test/SemaCXX/PR6562.cpp
new file mode 100644
index 000000000000..854d9b058bc3
--- /dev/null
+++ b/test/SemaCXX/PR6562.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct X { ~X(); };
+template <typename T>
+struct A {
+ struct B { X x; };
+ struct C : public B {
+ C() : B() { }
+ };
+};
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
index 81f68392d85a..4243c1c0ead4 100644
--- a/test/SemaCXX/decl-expr-ambiguity.cpp
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -10,7 +10,7 @@ void f() {
int(a)++; // expected-error {{expression is not assignable}}
__extension__ int(a)++; // expected-error {{expression is not assignable}}
__typeof(int)(a,5)<<a; // expected-error {{function-style cast to a builtin type can only take one argument}}
- void(a), ++a; // expected-warning {{expression result unused}}
+ void(a), ++a;
if (int(a)+1) {}
for (int(a)+1;;) {} // expected-warning {{expression result unused}}
a = sizeof(int()+1);
diff --git a/test/SemaCXX/warn-unused-value.cpp b/test/SemaCXX/warn-unused-value.cpp
new file mode 100644
index 000000000000..775c3cf01f24
--- /dev/null
+++ b/test/SemaCXX/warn-unused-value.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value %s
+
+// PR4806
+namespace test0 {
+ class Box {
+ public:
+ int i;
+ volatile int j;
+ };
+
+ void doit() {
+ // pointer to volatile has side effect (thus no warning)
+ Box* box = new Box;
+ box->i; // expected-warning {{expression result unused}}
+ box->j;
+ }
+}
diff --git a/test/SemaObjC/duplicate-property.m b/test/SemaObjC/duplicate-property.m
new file mode 100644
index 000000000000..bc1fe71a1546
--- /dev/null
+++ b/test/SemaObjC/duplicate-property.m
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface Foo {
+ id x;
+}
+@property (nonatomic, retain) id x; // expected-note{{property declared here}}
+@property (nonatomic, retain) id x; // expected-error{{property has a previous declaration}}
+@end
diff --git a/test/SemaObjC/warn-write-strings.m b/test/SemaObjC/warn-write-strings.m
new file mode 100644
index 000000000000..938f0be7721f
--- /dev/null
+++ b/test/SemaObjC/warn-write-strings.m
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s
+
+// PR4804
+char* x = "foo"; // expected-warning {{initializing 'char const [4]' discards qualifiers, expected 'char *'}}
diff --git a/test/SemaObjCXX/objc-pointer-conv.mm b/test/SemaObjCXX/objc-pointer-conv.mm
index c03e3aaad3db..144bda4390d5 100644
--- a/test/SemaObjCXX/objc-pointer-conv.mm
+++ b/test/SemaObjCXX/objc-pointer-conv.mm
@@ -24,3 +24,15 @@ void RandomFunc(CFMDRef theDict, const void *key, const void *value);
RandomFunc((CFMDRef)dict, key, objects[3]);
}
@end
+
+@interface I
+- (void) Meth : (I*) Arg;
+@end
+
+void Func (I* arg); // expected-note {{candidate function not viable: no known conversion from 'I const *' to 'I *' for 1st argument}}
+
+void foo(const I *p, I* sel) {
+ [sel Meth : p]; // expected-error {{incompatible type sending 'I const *', expected 'I *'}}
+ Func(p); // expected-error {{no matching function for call to 'Func'}}
+}
+
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
index 7b4c53cfe0d7..6e0d71159004 100644
--- a/test/SemaTemplate/instantiate-function-1.cpp
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -214,3 +214,9 @@ template<typename T> struct X;
template<typename T> struct Y : public X<T> {
Y& x() { return *this; }
};
+
+// Make sure our assertions don't get too uppity.
+namespace test0 {
+ template <class T> class A { void foo(T array[10]); };
+ template class A<int>;
+}
diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp
index 8df808d2569a..59df3c22aa1c 100644
--- a/test/SemaTemplate/virtual-member-functions.cpp
+++ b/test/SemaTemplate/virtual-member-functions.cpp
@@ -36,10 +36,10 @@ struct Base {
template<typename T>
struct Derived : Base<T> {
- virtual void foo() { } // expected-note {{in instantiation of member function 'Base<int>::~Base' requested here}}
+ virtual void foo() { }
};
-template struct Derived<int>;
+template struct Derived<int>; // expected-note {{in instantiation of member function 'Base<int>::~Base' requested here}}
template<typename T>
struct HasOutOfLineKey {
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index b52a32ed9b51..663b32fa1a06 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -1133,7 +1133,8 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
// We failed to load the ASTUnit, but we can still deserialize the
// diagnostics and emit them.
FileManager FileMgr;
- SourceManager SourceMgr;
+ Diagnostic Diag;
+ SourceManager SourceMgr(Diag);
// FIXME: Faked LangOpts!
LangOptions LangOpts;
llvm::SmallVector<StoredDiagnostic, 4> Diags;
@@ -2042,11 +2043,13 @@ CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]);
std::pair<FileID, unsigned> LocInfo
= CXXUnit->getSourceManager().getDecomposedLoc(Loc);
- std::pair<const char *,const char *> Buffer
- = CXXUnit->getSourceManager().getBufferData(LocInfo.first);
+ bool Invalid = false;
+ llvm::StringRef Buffer
+ = CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return createCXString("");
- return createCXString(llvm::StringRef(Buffer.first+LocInfo.second,
- CXTok.int_data[2]));
+ return createCXString(Buffer.substr(LocInfo.second, CXTok.int_data[2]));
}
CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) {
@@ -2095,15 +2098,17 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
return;
// Create a lexer
- std::pair<const char *,const char *> Buffer
- = SourceMgr.getBufferData(BeginLocInfo.first);
+ bool Invalid = false;
+ llvm::StringRef Buffer
+ = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid);
+
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
CXXUnit->getASTContext().getLangOptions(),
- Buffer.first, Buffer.first + BeginLocInfo.second, Buffer.second);
+ Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end());
Lex.SetCommentRetentionState(true);
// Lex tokens until we hit the end of the range.
- const char *EffectiveBufferEnd = Buffer.first + EndLocInfo.second;
+ const char *EffectiveBufferEnd = Buffer.data() + EndLocInfo.second;
llvm::SmallVector<CXToken, 32> CXTokens;
Token Tok;
do {
@@ -2125,12 +2130,16 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
CXTok.int_data[0] = CXToken_Literal;
CXTok.ptr_data = (void *)Tok.getLiteralData();
} else if (Tok.is(tok::identifier)) {
- // Lookup the identifier to determine whether we have a
+ // Lookup the identifier to determine whether we have a keyword.
std::pair<FileID, unsigned> LocInfo
= SourceMgr.getDecomposedLoc(Tok.getLocation());
- const char *StartPos
- = CXXUnit->getSourceManager().getBufferData(LocInfo.first).first +
- LocInfo.second;
+ bool Invalid = false;
+ llvm::StringRef Buf
+ = CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return;
+
+ const char *StartPos = Buf.data() + LocInfo.second;
IdentifierInfo *II
= CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos);
CXTok.int_data[0] = II->getTokenID() == tok::identifier?
diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports
index 5b9530052b51..fe0396d2b140 100644
--- a/tools/CIndex/CIndex.exports
+++ b/tools/CIndex/CIndex.exports
@@ -2,6 +2,12 @@ _clang_annotateTokens
_clang_codeComplete
_clang_codeCompleteGetDiagnostic
_clang_codeCompleteGetNumDiagnostics
+_clang_constructUSR_ObjCClass
+_clang_constructUSR_ObjCCategory
+_clang_constructUSR_ObjCIvar
+_clang_constructUSR_ObjCMethod
+_clang_constructUSR_ObjCProtocol
+_clang_constructUSR_ObjCProperty
_clang_createIndex
_clang_createTranslationUnit
_clang_createTranslationUnitFromSourceFile
diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp
index 3b7674ec0d1d..264e5064ddb4 100644
--- a/tools/CIndex/CIndexCodeCompletion.cpp
+++ b/tools/CIndex/CIndexCodeCompletion.cpp
@@ -187,6 +187,9 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief Diagnostics produced while performing code completion.
llvm::SmallVector<StoredDiagnostic, 8> Diagnostics;
+ /// \brief Diag object
+ Diagnostic Diag;
+
/// \brief Language options used to adjust source locations.
LangOptions LangOpts;
@@ -202,7 +205,7 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
};
AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
- : CXCodeCompleteResults(), Buffer(0) { }
+ : CXCodeCompleteResults(), Buffer(0), SourceMgr(Diag) { }
AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
for (unsigned I = 0, N = NumResults; I != N; ++I)
diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp
index 922f4b3fa73f..9dbbd3541e4c 100644
--- a/tools/CIndex/CIndexUSRs.cpp
+++ b/tools/CIndex/CIndexUSRs.cpp
@@ -29,23 +29,77 @@ class USRGenerator : public DeclVisitor<USRGenerator> {
bool IgnoreResults;
public:
USRGenerator(llvm::raw_ostream &out) : Out(out), IgnoreResults(false) {}
-
+
bool ignoreResults() const { return IgnoreResults; }
-
+
+ // Visitation methods from generating USRs from AST elements.
void VisitBlockDecl(BlockDecl *D);
void VisitDeclContext(DeclContext *D);
void VisitFieldDecl(FieldDecl *D);
void VisitFunctionDecl(FunctionDecl *D);
void VisitNamedDecl(NamedDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
- void VisitObjCContainerDecl(ObjCContainerDecl *CD);
+ void VisitObjCContainerDecl(ObjCContainerDecl *CD);
void VisitObjCMethodDecl(ObjCMethodDecl *MD);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitTagDecl(TagDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
+
+
+ /// String generation methods used both by the visitation methods
+ /// and from other clients that want to directly generate USRs. These
+ /// methods do not construct complete USRs (which incorporate the parents
+ /// of an AST element), but only the fragments concerning the AST element
+ /// itself.
+
+ /// Generate a USR fragment for a named declaration. This does
+ /// not include the USR component for the parent.
+ void GenNamedDecl(llvm::StringRef name);
+
+ /// Generate a USR for an Objective-C class.
+ void GenObjCClass(llvm::StringRef cls);
+ /// Generate a USR for an Objective-C class category.
+ void GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat);
+ /// Generate a USR fragment for an Objective-C instance variable. The
+ /// complete USR can be created by concatenating the USR for the
+ /// encompassing class with this USR fragment.
+ void GenObjCIvar(llvm::StringRef ivar);
+ /// Generate a USR fragment for an Objective-C method.
+ void GenObjCMethod(llvm::StringRef sel, bool isInstanceMethod);
+ /// Generate a USR fragment for an Objective-C property.
+ void GenObjCProperty(llvm::StringRef prop);
+ /// Generate a USR for an Objective-C protocol.
+ void GenObjCProtocol(llvm::StringRef prot);
+};
+
+class StringUSRGenerator {
+private:
+ llvm::SmallString<1024> StrBuf;
+ llvm::raw_svector_ostream Out;
+ USRGenerator UG;
+public:
+ StringUSRGenerator()
+ : Out(StrBuf), UG(Out) {}
+
+ llvm::StringRef str() {
+ return Out.str();
+ }
+
+ USRGenerator* operator->() { return &UG; }
+
+ template <typename T>
+ llvm::raw_svector_ostream &operator<<(const T &x) {
+ Out << x;
+ return Out;
+ }
};
+
} // end anonymous namespace
+//===----------------------------------------------------------------------===//
+// Generating USRs from ASTS.
+//===----------------------------------------------------------------------===//
+
void USRGenerator::VisitBlockDecl(BlockDecl *D) {
VisitDeclContext(D->getDeclContext());
// FIXME: Better support for anonymous blocks.
@@ -76,8 +130,8 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
void USRGenerator::VisitNamedDecl(NamedDecl *D) {
VisitDeclContext(D->getDeclContext());
const std::string &s = D->getNameAsString();
-// assert(!s.empty());
- Out << "@^" << s;
+ // assert(!s.empty());
+ GenNamedDecl(s);
}
void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
@@ -87,8 +141,8 @@ void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Visit(cast<Decl>(D->getDeclContext()));
- Out << (D->isInstanceMethod() ? "(im)" : "(cm)");
- Out << DeclarationName(D->getSelector()).getAsString();
+ GenObjCMethod(DeclarationName(D->getSelector()).getAsString(),
+ D->isInstanceMethod());
}
void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
@@ -97,29 +151,29 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
assert(false && "Invalid ObjC container.");
case Decl::ObjCInterface:
case Decl::ObjCImplementation:
- Out << "objc(cs)" << D->getName();
+ GenObjCClass(D->getName());
break;
case Decl::ObjCCategory: {
ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
- Out << "objc(cy)" << CD->getClassInterface()->getName()
- << '^' << CD->getName();
+ GenObjCCategory(CD->getClassInterface()->getName(),
+ CD->getName());
break;
}
case Decl::ObjCCategoryImpl: {
ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
- Out << "objc(cy)" << CD->getClassInterface()->getName()
- << '^' << CD->getName();
+ GenObjCCategory(CD->getClassInterface()->getName(),
+ CD->getName());
break;
}
case Decl::ObjCProtocol:
- Out << "objc(pl)" << cast<ObjCProtocolDecl>(D)->getName();
+ GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName());
break;
}
}
void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
Visit(cast<Decl>(D->getDeclContext()));
- Out << "(py)" << D->getName();
+ GenObjCProperty(D->getName());
}
void USRGenerator::VisitTagDecl(TagDecl *D) {
@@ -130,12 +184,12 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
case TagDecl::TK_union: Out << "@U^"; break;
case TagDecl::TK_enum: Out << "@E^"; break;
}
-
+
// FIXME: Better support for anonymous structures and enums.
const std::string &s = D->getNameAsString();
if (s.empty()) {
if (TypedefDecl *TD = D->getTypedefForAnonDecl())
- Out << "^anontd^" << TD->getNameAsString();
+ Out << "^anontd^" << TD->getNameAsString();
else
Out << "^anon";
}
@@ -146,36 +200,104 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
DeclContext *DC = D->getDeclContext();
if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
- Visit(DCN);
+ Visit(DCN);
Out << "typedef@" << D->getName();
}
-// FIXME: This is a skeleton implementation. It will be overhauled.
-static CXString ConstructUSR(Decl *D) {
- llvm::SmallString<1024> StrBuf;
- {
- llvm::raw_svector_ostream Out(StrBuf);
- USRGenerator UG(Out);
- UG.Visit(static_cast<Decl*>(D));
- if (UG.ignoreResults())
- return createCXString(NULL);
- }
-
- if (StrBuf.empty())
- return createCXString(NULL);
-
- // Return a copy of the string that must be disposed by the caller.
- return createCXString(StrBuf.str(), true);
-}
+//===----------------------------------------------------------------------===//
+// General purpose USR generation methods.
+//===----------------------------------------------------------------------===//
+
+void USRGenerator::GenNamedDecl(llvm::StringRef name) {
+ Out << "@^" << name;
+}
+
+void USRGenerator::GenObjCClass(llvm::StringRef cls) {
+ Out << "objc(cs)" << cls;
+}
+void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) {
+ Out << "objc(cy)" << cls << '^' << cat;
+}
+
+void USRGenerator::GenObjCIvar(llvm::StringRef ivar) {
+ GenNamedDecl(ivar);
+}
+
+void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) {
+ Out << (isInstanceMethod ? "(im)" : "(cm)") << meth;
+}
+
+void USRGenerator::GenObjCProperty(llvm::StringRef prop) {
+ Out << "(py)" << prop;
+}
+
+void USRGenerator::GenObjCProtocol(llvm::StringRef prot) {
+ Out << "objc(pl)" << prot;
+}
+
+//===----------------------------------------------------------------------===//
+// API hooks.
+//===----------------------------------------------------------------------===//
extern "C" {
CXString clang_getCursorUSR(CXCursor C) {
- if (Decl *D = cxcursor::getCursorDecl(C))
- return ConstructUSR(D);
-
- return createCXString(NULL);
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return createCXString(NULL);
+
+ StringUSRGenerator SUG;
+ SUG->Visit(static_cast<Decl*>(D));
+
+ if (SUG->ignoreResults() || SUG.str().empty())
+ return createCXString(NULL);
+
+ // Return a copy of the string that must be disposed by the caller.
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
+ StringUSRGenerator SUG;
+ SUG << clang_getCString(classUSR);
+ SUG->GenObjCIvar(name);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCMethod(const char *name,
+ unsigned isInstanceMethod,
+ CXString classUSR) {
+ StringUSRGenerator SUG;
+ SUG << clang_getCString(classUSR);
+ SUG->GenObjCMethod(name, isInstanceMethod);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCClass(const char *name) {
+ StringUSRGenerator SUG;
+ SUG->GenObjCClass(name);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCProtocol(const char *name) {
+ StringUSRGenerator SUG;
+ SUG->GenObjCProtocol(name);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCCategory(const char *class_name,
+ const char *category_name) {
+ StringUSRGenerator SUG;
+ SUG->GenObjCCategory(class_name, category_name);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCProperty(const char *property,
+ CXString classUSR) {
+ StringUSRGenerator SUG;
+ SUG << clang_getCString(classUSR);
+ SUG->GenObjCProperty(property);
+ return createCXString(SUG.str(), true);
}
} // end extern "C"
diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile
index 3e288623e5eb..650bcd3645d2 100644
--- a/tools/CIndex/Makefile
+++ b/tools/CIndex/Makefile
@@ -10,7 +10,7 @@
LEVEL = ../../../..
LIBRARYNAME = CIndex
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
# Include this here so we can get the configuration of the targets
# that have been configured for construction. We have to do this
diff --git a/tools/Makefile b/tools/Makefile
index 5a9c67421b78..bfd5ad12f93d 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -13,8 +13,7 @@ DIRS := driver CIndex c-index-test
include $(LEVEL)/Makefile.config
ifeq ($(OS), $(filter $(OS), Cygwin MingW))
-DIRS := $(filter $(DIRS), CIndex)
-DIRS := $(filter $(DIRS), c-index-test)
+DIRS := $(filter-out CIndex c-index-test, $(DIRS))
endif
include $(LEVEL)/Makefile.common
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index e5a9280a0cbe..6434cb4ef551 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -12,7 +12,7 @@ TOOLNAME = clang
ifndef CLANG_IS_PRODUCTION
TOOLALIAS = clang++
endif
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
# Clang tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
diff --git a/www/analyzer/index.html b/www/analyzer/index.html
index 335ca8b34aa1..082d35fdc488 100644
--- a/www/analyzer/index.html
+++ b/www/analyzer/index.html
@@ -27,7 +27,7 @@ tool</a> or <a href="/xcode.html">within Xcode</a>. The standalone tool is
invoked from the command-line, and is intended to be run in tandem with a build
of a codebase.</p>
-<p>The analyzer is 100% open source and are part of the <a
+<p>The analyzer is 100% open source and is part of the <a
href="http://clang.llvm.org">Clang</a> project. Like the rest of Clang, the
analyzer is implemented as a C++ library that can be used by other tools and
applications.</p>
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 3368167b7fab..63084b53a7e6 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="http://checker.minormatter.com/checker-236.tar.bz2">checker-236.tar.bz2</a></b> (built February 25, 2010)
+<b><a href="http://checker.minormatter.com/checker-237.tar.bz2">checker-237.tar.bz2</a></b> (built March 11, 2010)