diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2010-05-27 15:17:06 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2010-05-27 15:17:06 +0000 |
commit | d7279c4c177bca357ef96ff1379fd9bc420bfe83 (patch) | |
tree | 3558f327a6f9ab59c5d7a06528d84e1560445247 | |
parent | be17651f5cd2e94922c1b732bc8589e180698193 (diff) |
Update clang to r104832.vendor/clang/clang-r104832
Notes
Notes:
svn path=/vendor/clang/dist/; revision=208600
svn path=/vendor/clang/clang-r104832/; revision=208977; tag=vendor/clang/clang-r104832
486 files changed, 22043 insertions, 9947 deletions
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 6556bb4e6a8c..43733f779378 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -441,43 +441,42 @@ 1AA963AB10D8576800786C86 /* FullExpr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = FullExpr.h; path = clang/AST/FullExpr.h; sourceTree = "<group>"; tabWidth = 2; }; 1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; }; 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; tabWidth = 2; }; - 1ABD23B11182449800A48E65 /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = APValue.cpp; sourceTree = "<group>"; }; - 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTConsumer.cpp; sourceTree = "<group>"; }; - 1ABD23B31182449800A48E65 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTContext.cpp; sourceTree = "<group>"; }; - 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTDiagnostic.cpp; sourceTree = "<group>"; }; - 1ABD23B51182449800A48E65 /* ASTImporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTImporter.cpp; sourceTree = "<group>"; }; - 1ABD23B61182449800A48E65 /* AttrImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AttrImpl.cpp; sourceTree = "<group>"; }; - 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CXXInheritance.cpp; sourceTree = "<group>"; }; - 1ABD23B81182449800A48E65 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Decl.cpp; sourceTree = "<group>"; }; - 1ABD23B91182449800A48E65 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarationName.cpp; sourceTree = "<group>"; }; - 1ABD23BA1182449800A48E65 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclBase.cpp; sourceTree = "<group>"; }; - 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclCXX.cpp; sourceTree = "<group>"; }; - 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclFriend.cpp; sourceTree = "<group>"; }; - 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclGroup.cpp; sourceTree = "<group>"; }; - 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclObjC.cpp; sourceTree = "<group>"; }; - 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclPrinter.cpp; sourceTree = "<group>"; }; - 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclTemplate.cpp; sourceTree = "<group>"; }; - 1ABD23C11182449800A48E65 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Expr.cpp; sourceTree = "<group>"; }; - 1ABD23C21182449800A48E65 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExprConstant.cpp; sourceTree = "<group>"; }; - 1ABD23C31182449800A48E65 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExprCXX.cpp; sourceTree = "<group>"; }; - 1ABD23C41182449800A48E65 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FullExpr.cpp; sourceTree = "<group>"; }; - 1ABD23C51182449800A48E65 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InheritViz.cpp; sourceTree = "<group>"; }; - 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NestedNameSpecifier.cpp; sourceTree = "<group>"; }; - 1ABD23C71182449800A48E65 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParentMap.cpp; sourceTree = "<group>"; }; - 1ABD23C81182449800A48E65 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayout.cpp; sourceTree = "<group>"; }; - 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayoutBuilder.cpp; sourceTree = "<group>"; }; - 1ABD23CA1182449800A48E65 /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordLayoutBuilder.h; sourceTree = "<group>"; }; - 1ABD23CB1182449800A48E65 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Stmt.cpp; sourceTree = "<group>"; }; - 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtDumper.cpp; sourceTree = "<group>"; }; - 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtIterator.cpp; sourceTree = "<group>"; }; - 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtPrinter.cpp; sourceTree = "<group>"; }; - 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtProfile.cpp; sourceTree = "<group>"; }; - 1ABD23D01182449800A48E65 /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtViz.cpp; sourceTree = "<group>"; }; - 1ABD23D11182449800A48E65 /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateBase.cpp; sourceTree = "<group>"; }; - 1ABD23D21182449800A48E65 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateName.cpp; sourceTree = "<group>"; }; - 1ABD23D31182449800A48E65 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Type.cpp; sourceTree = "<group>"; }; - 1ABD23D41182449800A48E65 /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLoc.cpp; sourceTree = "<group>"; }; - 1ABD23D51182449800A48E65 /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypePrinter.cpp; sourceTree = "<group>"; }; + 1ABD23B11182449800A48E65 /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = APValue.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23B31182449800A48E65 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTContext.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTDiagnostic.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23B51182449800A48E65 /* ASTImporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTImporter.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23B61182449800A48E65 /* AttrImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = AttrImpl.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CXXInheritance.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23B81182449800A48E65 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Decl.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23B91182449800A48E65 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarationName.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23BA1182449800A48E65 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclBase.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclFriend.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclGroup.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclObjC.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclPrinter.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclTemplate.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C11182449800A48E65 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Expr.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C21182449800A48E65 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C31182449800A48E65 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C41182449800A48E65 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = FullExpr.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C51182449800A48E65 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = InheritViz.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = NestedNameSpecifier.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C71182449800A48E65 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ParentMap.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C81182449800A48E65 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayout.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23CB1182449800A48E65 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Stmt.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtDumper.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtIterator.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtPrinter.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23D01182449800A48E65 /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtViz.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23D11182449800A48E65 /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateBase.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23D21182449800A48E65 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateName.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23D31182449800A48E65 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Type.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23D41182449800A48E65 /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLoc.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ABD23D51182449800A48E65 /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TypePrinter.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInstance.cpp; path = lib/Frontend/CompilerInstance.cpp; sourceTree = "<group>"; }; 1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInvocation.cpp; path = lib/Frontend/CompilerInvocation.cpp; sourceTree = "<group>"; }; 1ACB57DD1105820D0047B991 /* DeclXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclXML.cpp; path = lib/Frontend/DeclXML.cpp; sourceTree = "<group>"; }; @@ -1494,7 +1493,6 @@ 1ABD23C71182449800A48E65 /* ParentMap.cpp */, 1ABD23C81182449800A48E65 /* RecordLayout.cpp */, 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */, - 1ABD23CA1182449800A48E65 /* RecordLayoutBuilder.h */, 1ABD23CB1182449800A48E65 /* Stmt.cpp */, 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */, 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */, diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html index daec6b019415..5ef5dd842a6d 100644 --- a/docs/InternalsManual.html +++ b/docs/InternalsManual.html @@ -532,12 +532,12 @@ source code of the program. Important design points include:</p> </ol> <p>In practice, the SourceLocation works together with the SourceManager class -to encode two pieces of information about a location: it's spelling location -and it's instantiation location. For most tokens, these will be the same. However, -for a macro expansion (or tokens that came from a _Pragma directive) these will -describe the location of the characters corresponding to the token and the -location where the token was used (i.e. the macro instantiation point or the -location of the _Pragma itself).</p> +to encode two pieces of information about a location: its spelling location +and its instantiation location. For most tokens, these will be the same. +However, for a macro expansion (or tokens that came from a _Pragma directive) +these will describe the location of the characters corresponding to the token +and the location where the token was used (i.e. the macro instantiation point +or the location of the _Pragma itself).</p> <p>The Clang front-end inherently depends on the location of a token being tracked correctly. If it is ever incorrect, the front-end may get confused and diff --git a/docs/UsersManual.html b/docs/UsersManual.html index 7d7f2631ab5e..5c5f6f916cf6 100644 --- a/docs/UsersManual.html +++ b/docs/UsersManual.html @@ -36,6 +36,7 @@ td { <ul> <li><a href="#diagnostics_display">Controlling How Clang Displays Diagnostics</a></li> <li><a href="#diagnostics_mappings">Diagnostic Mappings</a></li> + <li><a href="#diagnostics_categories">Diagnostic Categories</a><li> <li><a href="#diagnostics_commandline">Controlling Diagnostics via Command Line Flags</a></li> <li><a href="#diagnostics_pragmas">Controlling Diagnostics via Pragmas</a></li> </ul> @@ -286,6 +287,30 @@ diagnostic. This information tells you the flag needed to enable or disable the diagnostic, either from the command line or through <a href="#pragma_GCC_diagnostic">#pragma GCC diagnostic</a>.</dd> +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> +<dt id="opt_fdiagnostics-show-category"><b>-fdiagnostics-show-category=none/id/name</b>: +Enable printing category information in diagnostic line.</dt> +<dd>This option, which defaults to "none", +controls whether or not Clang prints the category associated with a diagnostic +when emitting it. Each diagnostic may or many not have an associated category, +if it has one, it is listed in the diagnostic categorization field of the +diagnostic line (in the []'s).</p> + +<p>For example, a format string warning will produce these three renditions +based on the setting of this option:</p> + +<pre> + t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat] + t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat<b>,1</b>] + t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat<b>,Format String</b>] +</pre> + +<p>This category can be used by clients that want to group diagnostics by +category, so it should be a high level category. We want dozens of these, not +hundreds or thousands of them.</p> +</dd> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <dt id="opt_fdiagnostics-fixit-info"><b>-f[no-]diagnostics-fixit-info</b>: @@ -393,6 +418,10 @@ it:</p> <li>An option that indicates how to control the diagnostic (for diagnostics that support it) [<a href="#opt_fdiagnostics-show-option">-fdiagnostics-show-option</a>].</li> +<li>A <a href="#diagnostics_categories">high-level category</a> for the + diagnostic for clients that want to group diagnostics by class (for + diagnostics that support it) [<a + href="#opt_fdiagnostics-show-category">-fdiagnostics-show-category</a>].</li> <li>The line of source code that the issue occurs on, along with a caret and ranges that indicate the important locations [<a href="opt_fcaret-diagnostics">-fcaret-diagnostics</a>].</li> @@ -407,6 +436,7 @@ it:</p> <p>For more information please see <a href="#cl_diag_formatting">Formatting of Diagnostics</a>.</p> + <h4 id="diagnostics_mappings">Diagnostic Mappings</h4> <p>All diagnostics are mapped into one of these 5 classes:</p> @@ -420,7 +450,23 @@ Diagnostics</a>.</p> <li>Fatal</li> </ul></p> -<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line Flags</h4> +<h4 id="diagnostics_categories">Diagnostic Categories</h4> + +<p>Though not shown by default, diagnostics may each be associated with a + high-level category. This category is intended to make it possible to triage + builds that produce a large number of errors or warnings in a grouped way. +</p> + +<p>Categories are not shown by default, but they can be turned on with the +<a href="#opt_fdiagnostics-show-category">-fdiagnostics-show-category</a> option. +When set to "<tt>name</tt>", the category is printed textually in the diagnostic +output. When it is set to "<tt>id</tt>", a category number is printed. The +mapping of category names to category id's can be obtained by running '<tt>clang + --print-diagnostic-categories</tt>'. +</p> + +<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line + Flags</h4> <p>-W flags, -pedantic, etc</p> diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod index 42cf8fa2d711..0c1ab574d535 100644 --- a/docs/tools/clang.pod +++ b/docs/tools/clang.pod @@ -50,10 +50,13 @@ parse errors. The output of this stage is an "Abstract Syntax Tree" (AST). =item B<Code Generation and Optimization> This stage translates an AST into low-level intermediate code (known as "LLVM -IR") and ultimately to machine code (depending on the optimization level). This -phase is responsible for optimizing the generated code and handling -target-specfic code generation. The output of this stage is typically called a -".s" file or "assembly" file. +IR") and ultimately to machine code. This phase is responsible for optimizing +the generated code and handling target-specfic code generation. The output of +this stage is typically called a ".s" file or "assembly" file. + +Clang also supports the use of an integrated assembler, in which the code +generator produces object files directly. This avoids the overhead of generating +the ".s" file and of calling the target assembler. =item B<Assembler> @@ -325,17 +328,21 @@ Pass I<arg> to the assembler. =item B<-Xclang> I<arg> -Pass I<arg> to the clang compiler. +Pass I<arg> to the clang compiler frontend. =item B<-Xlinker> I<arg> Pass I<arg> to the linker. +=item B<-mllvm> I<arg> + +Pass I<arg> to the LLVM backend. + =item B<-Xpreprocessor> I<arg> Pass I<arg> to the preprocessor. -=item B<-o> I<file> +=item B<-o> I<file> Write output to I<file>. @@ -359,6 +366,12 @@ Print the paths used for finding libraries and programs. Save intermediate compilation results. +=item B<-integrated-as> B<-no-integrated-as> + +Used to enable and disable, respectively, the use of the integrated +assembler. Whether the integrated assembler is on by default is target +dependent. + =item B<-time> Time individual commands. diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 1bf5a4688a2c..86926bd683ba 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -343,6 +343,12 @@ CINDEX_LINKAGE CXSourceLocation clang_getRangeStart(CXSourceRange range); CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range); /** + * \brief Determine if the source location occurs within the main file + * of the translation unit (as opposed to an included header). + */ +CINDEX_LINKAGE unsigned clang_isFromMainFile(CXSourceLocation loc); + +/** * @} */ @@ -648,7 +654,6 @@ CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); */ enum CXCursorKind { /* Declarations */ - CXCursor_FirstDecl = 1, /** * \brief A declaration whose specific kind is not exposed via this * interface. @@ -700,11 +705,15 @@ enum CXCursorKind { CXCursor_ObjCCategoryImplDecl = 19, /** \brief A typedef */ CXCursor_TypedefDecl = 20, - /** \brief A C++ class method. */ CXCursor_CXXMethod = 21, + /** \brief A C++ namespace. */ + CXCursor_Namespace = 22, + /** \brief A linkage specification, e.g. 'extern "C"'. */ + CXCursor_LinkageSpec = 23, - CXCursor_LastDecl = 21, + CXCursor_FirstDecl = CXCursor_UnexposedDecl, + CXCursor_LastDecl = CXCursor_LinkageSpec, /* References */ CXCursor_FirstRef = 40, /* Decl references */ @@ -807,7 +816,8 @@ enum CXCursorKind { CXCursor_IBActionAttr = 401, CXCursor_IBOutletAttr = 402, - CXCursor_LastAttr = CXCursor_IBOutletAttr, + CXCursor_IBOutletCollectionAttr = 403, + CXCursor_LastAttr = CXCursor_IBOutletCollectionAttr, /* Preprocessing */ CXCursor_PreprocessingDirective = 500, @@ -1021,6 +1031,124 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor); */ /** + * \defgroup CINDEX_TYPES Type information for CXCursors + * + * @{ + */ + +/** + * \brief Describes the kind of type + */ +enum CXTypeKind { + /** + * \brief Reprents an invalid type (e.g., where no type is available). + */ + CXType_Invalid = 0, + + /** + * \brief A type whose specific kind is not exposed via this + * interface. + */ + CXType_Unexposed = 1, + + /* Builtin types */ + CXType_Void = 2, + CXType_Bool = 3, + CXType_Char_U = 4, + CXType_UChar = 5, + CXType_Char16 = 6, + CXType_Char32 = 7, + CXType_UShort = 8, + CXType_UInt = 9, + CXType_ULong = 10, + CXType_ULongLong = 11, + CXType_UInt128 = 12, + CXType_Char_S = 13, + CXType_SChar = 14, + CXType_WChar = 15, + CXType_Short = 16, + CXType_Int = 17, + CXType_Long = 18, + CXType_LongLong = 19, + CXType_Int128 = 20, + CXType_Float = 21, + CXType_Double = 22, + CXType_LongDouble = 23, + CXType_NullPtr = 24, + CXType_Overload = 25, + CXType_Dependent = 26, + CXType_ObjCId = 27, + CXType_ObjCClass = 28, + CXType_ObjCSel = 29, + CXType_FirstBuiltin = CXType_Void, + CXType_LastBuiltin = CXType_ObjCSel, + + CXType_Complex = 100, + CXType_Pointer = 101, + CXType_BlockPointer = 102, + CXType_LValueReference = 103, + CXType_RValueReference = 104, + CXType_Record = 105, + CXType_Enum = 106, + CXType_Typedef = 107, + CXType_ObjCInterface = 108, + CXType_ObjCObjectPointer = 109 +}; + +/** + * \brief The type of an element in the abstract syntax tree. + * + */ +typedef struct { + enum CXTypeKind kind; + void *data[2]; +} CXType; + +/** + * \brief Retrieve the type of a CXCursor (if any). + */ +CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C); + +/** + * \determine Determine whether two CXTypes represent the same type. + * + * \returns non-zero if the CXTypes represent the same type and + zero otherwise. + */ +CINDEX_LINKAGE unsigned clang_equalTypes(CXType A, CXType B); + +/** + * \brief Return the canonical type for a CXType. + * + * Clang's type system explicitly models typedefs and all the ways + * a specific type can be represented. The canonical type is the underlying + * type with all the "sugar" removed. For example, if 'T' is a typedef + * for 'int', the canonical type for 'T' would be 'int'. + */ +CINDEX_LINKAGE CXType clang_getCanonicalType(CXType T); + +/** + * \brief For pointer types, returns the type of the pointee. + * + */ +CINDEX_LINKAGE CXType clang_getPointeeType(CXType T); + +/** + * \brief Return the cursor for the declaration of the given type. + */ +CINDEX_LINKAGE CXCursor clang_getTypeDeclaration(CXType T); + + +/** + * \brief Retrieve the spelling of a given CXTypeKind. + */ +CINDEX_LINKAGE CXString clang_getTypeKindSpelling(enum CXTypeKind K); + +/** + * @} + */ + +/** * \defgroup CINDEX_CURSOR_TRAVERSAL Traversing the AST with cursors * * These routines provide the ability to traverse the abstract syntax tree @@ -1220,6 +1348,24 @@ CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor); */ /** + * \defgroup CINDEX_CPP C++ AST introspection + * + * The routines in this group provide access information in the ASTs specific + * to C++ language features. + * + * @{ + */ + +/** + * \brief Determine if a C++ member function is declared 'static'. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C); + +/** + * @} + */ + +/** * \defgroup CINDEX_LEX Token extraction and manipulation * * The routines in this group provide access to the tokens within a @@ -1649,6 +1795,21 @@ CINDEX_LINKAGE unsigned clang_getNumCompletionChunks(CXCompletionString completion_string); /** + * \brief Determine the priority of this code completion. + * + * The priority of a code completion indicates how likely it is that this + * particular completion is the completion that the user will select. The + * priority is selected by various internal heuristics. + * + * \param completion_string The completion string to query. + * + * \returns The priority of this completion string. Smaller values indicate + * higher-priority (more likely) completions. + */ +CINDEX_LINKAGE unsigned +clang_getCompletionPriority(CXCompletionString completion_string); + +/** * \brief Contains the results of code-completion. * * This data structure contains the results of code completion, as diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h index 53bb785c49d2..06113954fc48 100644 --- a/include/clang/AST/ASTConsumer.h +++ b/include/clang/AST/ASTConsumer.h @@ -16,6 +16,7 @@ namespace clang { class ASTContext; + class CXXRecordDecl; class DeclGroupRef; class TagDecl; class HandleTagDeclDefinition; @@ -68,6 +69,17 @@ public: /// modified by the introduction of an implicit zero initializer. virtual void CompleteTentativeDefinition(VarDecl *D) {} + /// \brief Callback involved at the end of a translation unit to + /// notify the consumer that a vtable for the given C++ class is + /// required. + /// + /// \param RD The class whose vtable was used. + /// + /// \param DefinitionRequired Whether a definition of this vtable is + /// required in this translation unit; otherwise, it is only needed if + /// it was actually used. + virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {} + /// PrintStats - If desired, print any statistics. virtual void PrintStats() {} diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f8a8f179ae58..87a12cde2ad2 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -96,11 +96,10 @@ class ASTContext { llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; llvm::FoldingSet<SubstTemplateTypeParmType> SubstTemplateTypeParmTypes; llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes; - llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes; + llvm::FoldingSet<ElaboratedType> ElaboratedTypes; llvm::FoldingSet<DependentNameType> DependentNameTypes; - llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes; + llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes; llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes; - llvm::FoldingSet<ElaboratedType> ElaboratedTypes; llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; @@ -483,7 +482,7 @@ public: /// This gets the struct used to keep track of pointer to blocks, complete /// with captured variables. QualType getBlockParmType(bool BlockHasCopyDispose, - llvm::SmallVector<const Expr *, 8> &BDRDs); + llvm::SmallVectorImpl<const Expr *> &Layout); /// This builds the struct used for __block variables. QualType BuildByRefType(const char *DeclName, QualType Ty); @@ -613,8 +612,9 @@ public: const TemplateArgumentListInfo &Args, QualType Canon = QualType()); - QualType getQualifiedNameType(NestedNameSpecifier *NNS, - QualType NamedType); + QualType getElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + QualType NamedType); QualType getDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, @@ -623,19 +623,16 @@ public: NestedNameSpecifier *NNS, const TemplateSpecializationType *TemplateId, QualType Canon = QualType()); - QualType getElaboratedType(QualType UnderlyingType, - ElaboratedType::TagKind Tag); - QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **Protocols = 0, - unsigned NumProtocols = 0); + QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl); + + QualType getObjCObjectType(QualType Base, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols); - /// getObjCObjectPointerType - Return a ObjCObjectPointerType type for the - /// given interface decl and the conforming protocol list. - QualType getObjCObjectPointerType(QualType OIT, - ObjCProtocolDecl **ProtocolList = 0, - unsigned NumProtocols = 0, - unsigned Quals = 0); + /// getObjCObjectPointerType - Return a ObjCObjectPointerType type + /// for the given ObjCObjectType. + QualType getObjCObjectPointerType(QualType OIT); /// getTypeOfType - GCC extension. QualType getTypeOfExprType(Expr *e); @@ -913,6 +910,9 @@ public: CharUnits getTypeAlignInChars(QualType T); CharUnits getTypeAlignInChars(const Type *T); + std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T); + std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T); + /// getPreferredTypeAlign - Return the "preferred" alignment of the specified /// type for the current target in bits. This can be different than the ABI /// alignment in cases where it is beneficial for performance to overalign @@ -1184,8 +1184,8 @@ public: // Check the safety of assignment from LHS to RHS bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT); - bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS, - const ObjCInterfaceType *RHS); + bool canAssignObjCInterfaces(const ObjCObjectType *LHS, + const ObjCObjectType *RHS); bool canAssignObjCInterfacesInBlockPointer( const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT); @@ -1196,6 +1196,8 @@ public: // Functions for calculating composite types QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false); QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false); + + QualType mergeObjCGCQualifiers(QualType, QualType); /// UsualArithmeticConversionsType - handles the various conversions /// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9) @@ -1270,6 +1272,15 @@ public: TypeSourceInfo * getTrivialTypeSourceInfo(QualType T, SourceLocation Loc = SourceLocation()); + /// \brief Add a deallocation callback that will be invoked when the + /// ASTContext is destroyed. + /// + /// \brief Callback A callback function that will be invoked on destruction. + /// + /// \brief Data Pointer data that will be provided to the callback function + /// when it is called. + void AddDeallocation(void (*Callback)(void*), void *Data); + private: ASTContext(const ASTContext&); // DO NOT IMPLEMENT void operator=(const ASTContext&); // DO NOT IMPLEMENT @@ -1284,16 +1295,21 @@ private: const FieldDecl *Field, bool OutermostType = false, bool EncodingProperty = false); - + const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl); private: + /// \brief A set of deallocations that should be performed when the + /// ASTContext is destroyed. + llvm::SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations; + // FIXME: This currently contains the set of StoredDeclMaps used // by DeclContext objects. This probably should not be in ASTContext, // but we include it here so that ASTContext can quickly deallocate them. llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM; friend class DeclContext; + friend class DeclarationNameTable; void ReleaseDeclContextMaps(); }; diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 19744931762b..3240e50b0787 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -23,9 +23,10 @@ using llvm::dyn_cast; namespace clang { class ASTContext; + class IdentifierInfo; + class ObjCInterfaceDecl; } - // Defined in ASTContext.h void *operator new(size_t Bytes, clang::ASTContext &C, size_t Alignment = 16) throw (); @@ -44,6 +45,7 @@ public: enum Kind { Alias, Aligned, + AlignMac68k, AlwaysInline, AnalyzerNoReturn, // Clang-specific. Annotate, @@ -63,8 +65,10 @@ public: GNUInline, Hiding, IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro. + IBOutletCollectionKind, // Clang-specific. IBActionKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro. Malloc, + MaxFieldAlignment, NoDebug, NoInline, NonNull, @@ -79,13 +83,13 @@ public: NSReturnsNotRetained, // Clang/Checker-specific. Overloadable, // Clang-specific Packed, - PragmaPack, Pure, Regparm, ReqdWorkGroupSize, // OpenCL-specific Section, Sentinel, StdCall, + ThisCall, TransparentUnion, Unavailable, Unused, @@ -183,11 +187,14 @@ public: \ DEF_SIMPLE_ATTR(Packed); -class PragmaPackAttr : public Attr { +/// \brief Attribute for specifying a maximum field alignment; this is only +/// valid on record decls. +class MaxFieldAlignmentAttr : public Attr { unsigned Alignment; public: - PragmaPackAttr(unsigned alignment) : Attr(PragmaPack), Alignment(alignment) {} + MaxFieldAlignmentAttr(unsigned alignment) + : Attr(MaxFieldAlignment), Alignment(alignment) {} /// getAlignment - The specified alignment in bits. unsigned getAlignment() const { return Alignment; } @@ -196,11 +203,13 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { - return A->getKind() == PragmaPack; + return A->getKind() == MaxFieldAlignment; } - static bool classof(const PragmaPackAttr *A) { return true; } + static bool classof(const MaxFieldAlignmentAttr *A) { return true; } }; +DEF_SIMPLE_ATTR(AlignMac68k); + class AlignedAttr : public Attr { unsigned Alignment; public: @@ -317,6 +326,23 @@ public: static bool classof(const IBOutletAttr *A) { return true; } }; +class IBOutletCollectionAttr : public Attr { + const ObjCInterfaceDecl *D; +public: + IBOutletCollectionAttr(const ObjCInterfaceDecl *d = 0) + : Attr(IBOutletCollectionKind), D(d) {} + + const ObjCInterfaceDecl *getClass() const { return D; } + + virtual Attr *clone(ASTContext &C) const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() == IBOutletCollectionKind; + } + static bool classof(const IBOutletCollectionAttr *A) { return true; } +}; + class IBActionAttr : public Attr { public: IBActionAttr() : Attr(IBActionKind) {} @@ -457,6 +483,7 @@ public: DEF_SIMPLE_ATTR(FastCall); DEF_SIMPLE_ATTR(StdCall); +DEF_SIMPLE_ATTR(ThisCall); DEF_SIMPLE_ATTR(CDecl); DEF_SIMPLE_ATTR(TransparentUnion); DEF_SIMPLE_ATTR(ObjCNSObject); diff --git a/include/clang/AST/CMakeLists.txt b/include/clang/AST/CMakeLists.txt new file mode 100644 index 000000000000..c24ea06aa024 --- /dev/null +++ b/include/clang/AST/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_TARGET_DEFINITIONS StmtNodes.td) +tablegen(StmtNodes.inc + -gen-clang-stmt-nodes) +add_custom_target(ClangStmtNodes + DEPENDS StmtNodes.inc) diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h index edd633e8e140..5a84e404a1b6 100644 --- a/include/clang/AST/CXXInheritance.h +++ b/include/clang/AST/CXXInheritance.h @@ -196,7 +196,7 @@ public: /// \brief Determine whether the path from the most-derived type to the /// given base type is ambiguous (i.e., it refers to multiple subobjects of /// the same base type). - bool isAmbiguous(QualType BaseType); + bool isAmbiguous(CanQualType BaseType); /// \brief Whether we are finding multiple paths to detect ambiguities. bool isFindingAmbiguities() const { return FindAmbiguities; } diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 93dcad751221..4afb81dd05eb 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -643,6 +643,24 @@ struct CanProxyAdaptor<TemplateTypeParmType> }; template<> +struct CanProxyAdaptor<ObjCObjectType> + : public CanProxyBase<ObjCObjectType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceDecl *, + getInterface) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedId) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedClass) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedId) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClass) + + typedef ObjCObjectPointerType::qual_iterator qual_iterator; + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols) +}; + +template<> struct CanProxyAdaptor<ObjCObjectPointerType> : public CanProxyBase<ObjCObjectPointerType> { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 834c9a0c563f..7d5b66e02a28 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -55,7 +55,7 @@ public: QualType getType() const { return Ty; } /// \brief Return the TypeLoc wrapper for the type source info. - TypeLoc getTypeLoc() const; + TypeLoc getTypeLoc() const; // implemented in TypeLoc.h }; /// TranslationUnitDecl - The top declaration context. @@ -138,6 +138,8 @@ public: // FIXME: Deprecated, move clients to getName(). std::string getNameAsString() const { return Name.getAsString(); } + void printName(llvm::raw_ostream &os) const { return Name.printName(os); } + /// getDeclName - Get the actual, stored name of the declaration, /// which may be a special name. DeclarationName getDeclName() const { return Name; } @@ -265,18 +267,25 @@ public: // \brief Returns true if this is an anonymous namespace declaration. // // For example: + /// \code // namespace { // ... // }; + // \endcode // q.v. C++ [namespace.unnamed] bool isAnonymousNamespace() const { return !getIdentifier(); } + /// \brief Return the next extended namespace declaration or null if this + /// is none. NamespaceDecl *getNextNamespace() { return NextNamespace; } const NamespaceDecl *getNextNamespace() const { return NextNamespace; } + + /// \brief Set the next extended namespace declaration. void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; } + /// \brief Get the original (first) namespace declaration. NamespaceDecl *getOriginalNamespace() const { if (OrigOrAnonNamespace.getInt()) return const_cast<NamespaceDecl *>(this); @@ -284,6 +293,14 @@ public: return OrigOrAnonNamespace.getPointer(); } + /// \brief Return true if this declaration is an original (first) declaration + /// of the namespace. This is false for non-original (subsequent) namespace + /// declarations and anonymous namespaces. + bool isOriginalNamespace() const { + return getOriginalNamespace() == this; + } + + /// \brief Set the original (first) namespace declaration. void setOriginalNamespace(NamespaceDecl *ND) { if (ND != this) { OrigOrAnonNamespace.setPointer(ND); @@ -502,6 +519,10 @@ private: /// or an Objective-C @catch statement. bool ExceptionVar : 1; + /// \brief Whether this local variable could be allocated in the return + /// slot of its function, enabling the named return value optimization (NRVO). + bool NRVOVariable : 1; + friend class StmtIteratorBase; protected: VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, @@ -509,7 +530,7 @@ protected: StorageClass SCAsWritten) : DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(), ThreadSpecified(false), HasCXXDirectInit(false), - DeclaredInCondition(false), ExceptionVar(false) { + DeclaredInCondition(false), ExceptionVar(false), NRVOVariable(false) { SClass = SC; SClassAsWritten = SCAsWritten; } @@ -852,6 +873,19 @@ public: } void setExceptionVariable(bool EV) { ExceptionVar = EV; } + /// \brief Determine whether this local variable can be used with the named + /// return value optimization (NRVO). + /// + /// The named return value optimization (NRVO) works by marking certain + /// non-volatile local variables of class type as NRVO objects. These + /// locals can be allocated within the return slot of their containing + /// function, in which case there is no need to copy the object to the + /// return slot when returning from the function. Within the function body, + /// each return that returns the NRVO object will have this variable as its + /// NRVO candidate. + bool isNRVOVariable() const { return NRVOVariable; } + void setNRVOVariable(bool NRVO) { NRVOVariable = NRVO; } + /// \brief If this variable is an instantiated static data member of a /// class template specialization, returns the templated static data member /// from which it was instantiated. @@ -1390,6 +1424,16 @@ public: /// returns NULL. const TemplateArgumentList *getTemplateSpecializationArgs() const; + /// \brief Retrieve the template argument list as written in the sources, + /// if any. + /// + /// If this function declaration is not a function template specialization + /// or if it had no explicit template argument list, returns NULL. + /// Note that it an explicit template argument list may be written empty, + /// e.g., template<> void foo<>(char* s); + const TemplateArgumentListInfo* + getTemplateSpecializationArgsAsWritten() const; + /// \brief Specify that this function declaration is actually a function /// template specialization. /// @@ -1409,7 +1453,8 @@ public: void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, void *InsertPos, - TemplateSpecializationKind TSK = TSK_ImplicitInstantiation); + TemplateSpecializationKind TSK = TSK_ImplicitInstantiation, + const TemplateArgumentListInfo *TemplateArgsAsWritten = 0); /// \brief Specifies that this function declaration is actually a /// dependent function template specialization. @@ -1593,7 +1638,19 @@ class TypedefDecl : public TypeDecl, public Redeclarable<TypedefDecl> { : TypeDecl(Typedef, DC, L, Id), TInfo(TInfo) {} virtual ~TypedefDecl(); + +protected: + typedef Redeclarable<TypedefDecl> redeclarable_base; + virtual TypedefDecl *getNextRedeclaration() { return RedeclLink.getNext(); } + public: + typedef redeclarable_base::redecl_iterator redecl_iterator; + redecl_iterator redecls_begin() const { + return redeclarable_base::redecls_begin(); + } + redecl_iterator redecls_end() const { + return redeclarable_base::redecls_end(); + } static TypedefDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, @@ -1631,11 +1688,7 @@ class TagDecl : public TypeDecl, public DeclContext, public Redeclarable<TagDecl> { public: // This is really ugly. - typedef ElaboratedType::TagKind TagKind; - static const TagKind TK_struct = ElaboratedType::TK_struct; - static const TagKind TK_union = ElaboratedType::TK_union; - static const TagKind TK_class = ElaboratedType::TK_class; - static const TagKind TK_enum = ElaboratedType::TK_enum; + typedef TagTypeKind TagKind; private: // FIXME: This can be packed into the bitfields in Decl. @@ -1651,6 +1704,12 @@ private: /// in the syntax of a declarator. bool IsEmbeddedInDeclarator : 1; +protected: + // These are used by (and only defined for) EnumDecl. + unsigned NumPositiveBits : 8; + unsigned NumNegativeBits : 8; + +private: SourceLocation TagKeywordLoc; SourceLocation RBraceLoc; @@ -1680,7 +1739,8 @@ protected: 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"); + assert((DK != Enum || TK == TTK_Enum) && + "EnumDecl not matched with TTK_Enum"); TagDeclKind = TK; IsDefinition = false; IsEmbeddedInDeclarator = false; @@ -1753,30 +1813,26 @@ public: void setDefinition(bool V) { IsDefinition = V; } const char *getKindName() const { - return ElaboratedType::getNameForTagKind(getTagKind()); + return TypeWithKeyword::getTagTypeKindName(getTagKind()); } - /// getTagKindForTypeSpec - Converts a type specifier (DeclSpec::TST) - /// into a tag kind. It is an error to provide a type specifier - /// which *isn't* a tag kind here. - static TagKind getTagKindForTypeSpec(unsigned TypeSpec); - TagKind getTagKind() const { return TagKind(TagDeclKind); } void setTagKind(TagKind TK) { TagDeclKind = TK; } - bool isStruct() const { return getTagKind() == TK_struct; } - bool isClass() const { return getTagKind() == TK_class; } - bool isUnion() const { return getTagKind() == TK_union; } - bool isEnum() const { return getTagKind() == TK_enum; } + bool isStruct() const { return getTagKind() == TTK_Struct; } + bool isClass() const { return getTagKind() == TTK_Class; } + bool isUnion() const { return getTagKind() == TTK_Union; } + bool isEnum() const { return getTagKind() == TTK_Enum; } TypedefDecl *getTypedefForAnonDecl() const { return hasExtInfo() ? 0 : TypedefDeclOrQualifier.get<TypedefDecl*>(); } - void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefDeclOrQualifier = TDD; } - + + void setTypedefForAnonDecl(TypedefDecl *TDD); + NestedNameSpecifier *getQualifier() const { return hasExtInfo() ? TypedefDeclOrQualifier.get<ExtInfo*>()->NNS : 0; } @@ -1820,9 +1876,16 @@ class EnumDecl : public TagDecl { /// enumeration declared within the template. EnumDecl *InstantiatedFrom; + // The number of positive and negative bits required by the + // enumerators are stored in the SubclassBits field. + enum { + NumBitsWidth = 8, + NumBitsMask = (1 << NumBitsWidth) - 1 + }; + EnumDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL) - : TagDecl(Enum, TK_enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) { + : TagDecl(Enum, TTK_Enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) { IntegerType = QualType(); } public: @@ -1845,7 +1908,9 @@ public: /// added (via DeclContext::addDecl). NewType is the new underlying /// type of the enumeration type. void completeDefinition(QualType NewType, - QualType PromotionType); + QualType PromotionType, + unsigned NumPositiveBits, + unsigned NumNegativeBits); // enumerator_iterator - Iterates through the enumerators of this // enumeration. @@ -1873,6 +1938,32 @@ public: /// \brief Set the underlying integer type. void setIntegerType(QualType T) { IntegerType = T; } + /// \brief Returns the width in bits requred to store all the + /// non-negative enumerators of this enum. + unsigned getNumPositiveBits() const { + return NumPositiveBits; + } + void setNumPositiveBits(unsigned Num) { + NumPositiveBits = Num; + assert(NumPositiveBits == Num && "can't store this bitcount"); + } + + /// \brief Returns the width in bits requred to store all the + /// negative enumerators of this enum. These widths include + /// the rightmost leading 1; that is: + /// + /// MOST NEGATIVE ENUMERATOR PATTERN NUM NEGATIVE BITS + /// ------------------------ ------- ----------------- + /// -1 1111111 1 + /// -10 1110110 5 + /// -101 1001011 8 + unsigned getNumNegativeBits() const { + return NumNegativeBits; + } + void setNumNegativeBits(unsigned Num) { + NumNegativeBits = Num; + } + /// \brief Returns the enumeration (declared within the template) /// from which this enumeration type was instantiated, or NULL if /// this enumeration was not instantiated from any template. @@ -1942,6 +2033,11 @@ public: AnonymousStructOrUnion = Anon; } + ValueDecl *getAnonymousStructOrUnionObject(); + const ValueDecl *getAnonymousStructOrUnionObject() const { + return const_cast<RecordDecl*>(this)->getAnonymousStructOrUnionObject(); + } + bool hasObjectMember() const { return HasObjectMember; } void setHasObjectMember (bool val) { HasObjectMember = val; } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index a9b948eee546..c15aeef14ba6 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -76,6 +76,11 @@ public: #include "clang/AST/DeclNodes.def" }; + /// \brief A placeholder type used to construct an empty shell of a + /// decl-derived type that will be filled in later (e.g., by some + /// deserialization method). + struct EmptyShell { }; + /// IdentifierNamespace - The different namespaces in which /// declarations may appear. According to C99 6.2.3, there are /// four namespaces, labels, tags, members and ordinary diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index aa649c811115..c19c200f265d 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1061,10 +1061,6 @@ class CXXBaseOrMemberInitializer { /// In above example, BaseOrMember holds the field decl. for anonymous union /// and AnonUnionMember holds field decl for au_i1. FieldDecl *AnonUnionMember; - - /// IsVirtual - If the initializer is a base initializer, this keeps track - /// of whether the base is virtual or not. - bool IsVirtual; /// LParenLoc - Location of the left paren of the ctor-initializer. SourceLocation LParenLoc; @@ -1072,6 +1068,28 @@ class CXXBaseOrMemberInitializer { /// RParenLoc - Location of the right paren of the ctor-initializer. SourceLocation RParenLoc; + /// IsVirtual - If the initializer is a base initializer, this keeps track + /// of whether the base is virtual or not. + bool IsVirtual : 1; + + /// IsWritten - Whether or not the initializer is explicitly written + /// in the sources. + bool IsWritten : 1; + /// SourceOrderOrNumArrayIndices - If IsWritten is true, then this + /// number keeps track of the textual order of this initializer in the + /// original sources, counting from 0; otherwise, if IsWritten is false, + /// it stores the number of array index variables stored after this + /// object in memory. + unsigned SourceOrderOrNumArrayIndices : 14; + + CXXBaseOrMemberInitializer(ASTContext &Context, + FieldDecl *Member, SourceLocation MemberLoc, + SourceLocation L, + Expr *Init, + SourceLocation R, + VarDecl **Indices, + unsigned NumIndices); + public: /// CXXBaseOrMemberInitializer - Creates a new base-class initializer. explicit @@ -1089,6 +1107,17 @@ public: Expr *Init, SourceLocation R); + /// \brief Creates a new member initializer that optionally contains + /// array indices used to describe an elementwise initialization. + static CXXBaseOrMemberInitializer *Create(ASTContext &Context, + FieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, + Expr *Init, + SourceLocation R, + VarDecl **Indices, + unsigned NumIndices); + /// \brief Destroy the base or member initializer. void Destroy(ASTContext &Context); @@ -1146,6 +1175,30 @@ public: /// \brief Determine the source range covering the entire initializer. SourceRange getSourceRange() const; + + /// isWritten - Returns true if this initializer is explicitly written + /// in the source code. + bool isWritten() const { return IsWritten; } + + /// \brief Return the source position of the initializer, counting from 0. + /// If the initializer was implicit, -1 is returned. + int getSourceOrder() const { + return IsWritten ? static_cast<int>(SourceOrderOrNumArrayIndices) : -1; + } + + /// \brief Set the source order of this initializer. This method can only + /// be called once for each initializer; it cannot be called on an + /// initializer having a positive number of (implicit) array indices. + void setSourceOrder(int pos) { + assert(!IsWritten && + "calling twice setSourceOrder() on the same initializer"); + assert(SourceOrderOrNumArrayIndices == 0 && + "setSourceOrder() used when there are implicit array indices"); + assert(pos >= 0 && + "setSourceOrder() used to make an initializer implicit"); + IsWritten = true; + SourceOrderOrNumArrayIndices = static_cast<unsigned>(pos); + } FieldDecl *getAnonUnionMember() const { return AnonUnionMember; @@ -1154,9 +1207,31 @@ public: AnonUnionMember = anonMember; } + SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } + /// \brief Determine the number of implicit array indices used while + /// described an array member initialization. + unsigned getNumArrayIndices() const { + return IsWritten ? 0 : SourceOrderOrNumArrayIndices; + } + + /// \brief Retrieve a particular array index variable used to + /// describe an array member initialization. + VarDecl *getArrayIndex(unsigned I) { + assert(I < getNumArrayIndices() && "Out of bounds member array index"); + return reinterpret_cast<VarDecl **>(this + 1)[I]; + } + const VarDecl *getArrayIndex(unsigned I) const { + assert(I < getNumArrayIndices() && "Out of bounds member array index"); + return reinterpret_cast<const VarDecl * const *>(this + 1)[I]; + } + void setArrayIndex(unsigned I, VarDecl *Index) { + assert(I < getNumArrayIndices() && "Out of bounds member array index"); + reinterpret_cast<VarDecl **>(this + 1)[I] = Index; + } + Expr *getInit() { return static_cast<Expr *>(Init); } }; @@ -1201,6 +1276,7 @@ class CXXConstructorDecl : public CXXMethodDecl { virtual void Destroy(ASTContext& C); public: + static CXXConstructorDecl *Create(ASTContext &C, EmptyShell Empty); static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, @@ -1343,6 +1419,7 @@ class CXXDestructorDecl : public CXXMethodDecl { } public: + static CXXDestructorDecl *Create(ASTContext& C, EmptyShell Empty); static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isInline, @@ -1398,6 +1475,7 @@ class CXXConversionDecl : public CXXMethodDecl { IsExplicitSpecified(isExplicitSpecified) { } public: + static CXXConversionDecl *Create(ASTContext &C, EmptyShell Empty); static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, @@ -1438,8 +1516,10 @@ public: /// ASTs and cannot be changed without altering that abi. To help /// ensure a stable abi for this, we choose the DW_LANG_ encodings /// from the dwarf standard. - enum LanguageIDs { lang_c = /* DW_LANG_C */ 0x0002, - lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 }; + enum LanguageIDs { + lang_c = /* DW_LANG_C */ 0x0002, + lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 + }; private: /// Language - The language for this linkage specification. LanguageIDs Language; @@ -1457,12 +1537,20 @@ public: SourceLocation L, LanguageIDs Lang, bool Braces); + /// \brief Return the language specified by this linkage specification. LanguageIDs getLanguage() const { return Language; } - /// hasBraces - Determines whether this linkage specification had - /// braces in its syntactic form. + /// \brief Set the language specified by this linkage specification. + void setLanguage(LanguageIDs L) { Language = L; } + + /// \brief Determines whether this linkage specification had braces in + /// its syntactic form. bool hasBraces() const { return HadBraces; } + /// \brief Set whether this linkage specification has braces in its + /// syntactic form. + void setHasBraces(bool B) { HadBraces = B; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const LinkageSpecDecl *D) { return true; } static bool classofKind(Kind K) { return K == LinkageSpec; } @@ -1528,13 +1616,21 @@ class UsingDirectiveDecl : public NamedDecl { public: /// \brief Retrieve the source range of the nested-name-specifier - /// that qualifiers the namespace name. + /// that qualifies the namespace name. SourceRange getQualifierRange() const { return QualifierRange; } + /// \brief Set the source range of the nested-name-specifier that + /// qualifies the namespace name. + void setQualifierRange(SourceRange R) { QualifierRange = R; } + /// \brief Retrieve the nested-name-specifier that qualifies the /// name of the namespace. NestedNameSpecifier *getQualifier() const { return Qualifier; } + /// \brief Set the nested-name-specifier that qualifes the name of the + /// namespace. + void setQualifier(NestedNameSpecifier *NNS) { Qualifier = NNS; } + NamedDecl *getNominatedNamespaceAsWritten() { return NominatedNamespace; } const NamedDecl *getNominatedNamespaceAsWritten() const { return NominatedNamespace; @@ -1547,17 +1643,32 @@ public: return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace(); } - /// getCommonAncestor - returns common ancestor context of using-directive, - /// and nominated by it namespace. + /// setNominatedNamespace - Set the namespace nominataed by the + /// using-directive. + void setNominatedNamespace(NamedDecl* NS); + + /// \brief Returns the common ancestor context of this using-directive and + /// its nominated namespace. DeclContext *getCommonAncestor() { return CommonAncestor; } const DeclContext *getCommonAncestor() const { return CommonAncestor; } + /// \brief Set the common ancestor context of this using-directive and its + /// nominated namespace. + void setCommonAncestor(DeclContext* Cxt) { CommonAncestor = Cxt; } + + // FIXME: Could omit 'Key' in name. /// getNamespaceKeyLocation - Returns location of namespace keyword. SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; } + /// setNamespaceKeyLocation - Set the the location of the namespacekeyword. + void setNamespaceKeyLocation(SourceLocation L) { NamespaceLoc = L; } + /// getIdentLocation - Returns location of identifier. SourceLocation getIdentLocation() const { return IdentLoc; } + /// setIdentLocation - set the location of the identifier. + void setIdentLocation(SourceLocation L) { IdentLoc = L; } + static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, SourceLocation NamespaceLoc, @@ -1591,7 +1702,7 @@ class NamespaceAliasDecl : public NamedDecl { /// name, if any. NestedNameSpecifier *Qualifier; - /// IdentLoc - Location of namespace identifier. + /// IdentLoc - Location of namespace identifier. Accessed by TargetNameLoc. SourceLocation IdentLoc; /// Namespace - The Decl that this alias points to. Can either be a @@ -1612,10 +1723,19 @@ public: /// that qualifiers the namespace name. SourceRange getQualifierRange() const { return QualifierRange; } + /// \brief Set the source range of the nested-name-specifier that qualifies + /// the namespace name. + void setQualifierRange(SourceRange R) { QualifierRange = R; } + /// \brief Retrieve the nested-name-specifier that qualifies the /// name of the namespace. NestedNameSpecifier *getQualifier() const { return Qualifier; } + /// \brief Set the nested-name-specifier that qualifies the name of the + /// namespace. + void setQualifier(NestedNameSpecifier *NNS) { Qualifier = NNS; } + + /// \brief Retrieve the namespace declaration aliased by this directive. NamespaceDecl *getNamespace() { if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(Namespace)) return AD->getNamespace(); @@ -1631,16 +1751,31 @@ public: /// "namespace foo = ns::bar;". SourceLocation getAliasLoc() const { return AliasLoc; } + /// Set the location o;f the alias name, e.e., 'foo' in + /// "namespace foo = ns::bar;". + void setAliasLoc(SourceLocation L) { AliasLoc = L; } + /// Returns the location of the 'namespace' keyword. SourceLocation getNamespaceLoc() const { return getLocation(); } /// Returns the location of the identifier in the named namespace. SourceLocation getTargetNameLoc() const { return IdentLoc; } + /// Set the location of the identifier in the named namespace. + void setTargetNameLoc(SourceLocation L) { IdentLoc = L; } + /// \brief Retrieve the namespace that this alias refers to, which /// may either be a NamespaceDecl or a NamespaceAliasDecl. NamedDecl *getAliasedNamespace() const { return Namespace; } + /// \brief Set the namespace or namespace alias pointed to by this + /// alias decl. + void setAliasedNamespace(NamedDecl *ND) { + assert((isa<NamespaceAliasDecl>(ND) || isa<NamespaceDecl>(ND)) && + "expecting namespace or namespace alias decl"); + Namespace = ND; + } + static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, SourceLocation AliasLoc, IdentifierInfo *Alias, @@ -1687,16 +1822,20 @@ public: return new (C) UsingShadowDecl(DC, Loc, Using, Target); } - /// Gets the underlying declaration which has been brought into the + /// \brief Gets the underlying declaration which has been brought into the /// local scope. - NamedDecl *getTargetDecl() const { - return Underlying; - } + NamedDecl *getTargetDecl() const { return Underlying; } - /// Gets the using declaration to which this declaration is tied. - UsingDecl *getUsingDecl() const { - return Using; - } + /// \brief Sets the underlying declaration which has been brought into the + /// local scope. + void setTargetDecl(NamedDecl* ND) { Underlying = ND; } + + /// \brief Gets the using declaration to which this declaration is tied. + UsingDecl *getUsingDecl() const { return Using; } + + /// \brief Sets the using declaration that introduces this target + /// declaration. + void setUsingDecl(UsingDecl* UD) { Using = UD; } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const UsingShadowDecl *D) { return true; } @@ -1733,21 +1872,39 @@ class UsingDecl : public NamedDecl { } public: + // FIXME: Should be const? /// \brief Returns the source range that covers the nested-name-specifier /// preceding the namespace name. SourceRange getNestedNameRange() { return NestedNameRange; } - /// \brief Returns the source location of the "using" location itself. + /// \brief Set the source range of the nested-name-specifier. + void setNestedNameRange(SourceRange R) { NestedNameRange = R; } + + // FIXME; Should be const? + // FIXME: Naming is inconsistent with other get*Loc functions. + /// \brief Returns the source location of the "using" keyword. SourceLocation getUsingLocation() { return UsingLocation; } - /// \brief Get target nested name declaration. + /// \brief Set the source location of the 'using' keyword. + void setUsingLocation(SourceLocation L) { UsingLocation = L; } + + + /// \brief Get the target nested name declaration. NestedNameSpecifier* getTargetNestedNameDecl() { return TargetNestedName; } - /// isTypeName - Return true if using decl has 'typename'. + /// \brief Set the target nested name declaration. + void setTargetNestedNameDecl(NestedNameSpecifier *NNS) { + TargetNestedName = NNS; + } + + /// \brief Return true if the using declaration has 'typename'. bool isTypeName() const { return IsTypeName; } + /// \brief Sets whether the using declaration has 'typename'. + void setTypeName(bool TN) { IsTypeName = TN; } + typedef llvm::SmallPtrSet<UsingShadowDecl*,8>::const_iterator shadow_iterator; shadow_iterator shadow_begin() const { return Shadows.begin(); } shadow_iterator shadow_end() const { return Shadows.end(); } @@ -1765,6 +1922,12 @@ public: } } + /// \brief Return the number of shadowed declarations associated with this + /// using declaration. + unsigned getNumShadowDecls() const { + return Shadows.size(); + } + static UsingDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation IdentL, SourceRange NNR, SourceLocation UsingL, NestedNameSpecifier* TargetNNS, DeclarationName Name, bool IsTypeNameArg); @@ -1807,14 +1970,26 @@ public: /// preceding the namespace name. SourceRange getTargetNestedNameRange() const { return TargetNestedNameRange; } + /// \brief Set the source range coverting the nested-name-specifier preceding + /// the namespace name. + void setTargetNestedNameRange(SourceRange R) { TargetNestedNameRange = R; } + /// \brief Get target nested name declaration. NestedNameSpecifier* getTargetNestedNameSpecifier() { return TargetNestedNameSpecifier; } + /// \brief Set the nested name declaration. + void setTargetNestedNameSpecifier(NestedNameSpecifier* NNS) { + TargetNestedNameSpecifier = NNS; + } + /// \brief Returns the source location of the 'using' keyword. SourceLocation getUsingLoc() const { return UsingLocation; } + /// \brief Set the source location of the 'using' keyword. + void setUsingLoc(SourceLocation L) { UsingLocation = L; } + static UnresolvedUsingValueDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, SourceRange TargetNNR, NestedNameSpecifier *TargetNNS, @@ -1861,17 +2036,32 @@ public: /// preceding the namespace name. SourceRange getTargetNestedNameRange() const { return TargetNestedNameRange; } + /// \brief Set the source range coverting the nested-name-specifier preceding + /// the namespace name. + void setTargetNestedNameRange(SourceRange R) { TargetNestedNameRange = R; } + /// \brief Get target nested name declaration. NestedNameSpecifier* getTargetNestedNameSpecifier() { return TargetNestedNameSpecifier; } + /// \brief Set the nested name declaration. + void setTargetNestedNameSpecifier(NestedNameSpecifier* NNS) { + TargetNestedNameSpecifier = NNS; + } + /// \brief Returns the source location of the 'using' keyword. SourceLocation getUsingLoc() const { return UsingLocation; } + /// \brief Set the source location of the 'using' keyword. + void setUsingLoc(SourceLocation L) { UsingLocation = L; } + /// \brief Returns the source location of the 'typename' keyword. SourceLocation getTypenameLoc() const { return TypenameLocation; } + /// \brief Set the source location of the 'typename' keyword. + void setTypenameLoc(SourceLocation L) { TypenameLocation = L; } + static UnresolvedUsingTypenameDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, SourceLocation TypenameLoc, diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h index 2a4b12ac2eaf..9602b677fca5 100644 --- a/include/clang/AST/DeclContextInternals.h +++ b/include/clang/AST/DeclContextInternals.h @@ -156,7 +156,8 @@ public: /// represents. DeclContext::lookup_result getLookupResult(ASTContext &Context) { if (isNull()) - return DeclContext::lookup_result(0, 0); + return DeclContext::lookup_result(DeclContext::lookup_iterator(0), + DeclContext::lookup_iterator(0)); if (hasDeclarationIDs()) materializeDecls(Context); diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index e34ec9ffcdf0..97d165696aad 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -1421,13 +1421,21 @@ private: /// Null for @dynamic. Required for @synthesize. ObjCIvarDecl *PropertyIvarDecl; + + /// Null for @dynamic. Non-null if property must be copy-constructed in getter + Expr *GetterCXXConstructor; + + /// Null for @dynamic. Non-null if property has assignment operator to call + /// in Setter synthesis. + Expr *SetterCXXAssignment; ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L, ObjCPropertyDecl *property, Kind PK, ObjCIvarDecl *ivarDecl) : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), - PropertyDecl(property), PropertyIvarDecl(ivarDecl) { + PropertyDecl(property), PropertyIvarDecl(ivarDecl), + GetterCXXConstructor(0), SetterCXXAssignment(0) { assert (PK == Dynamic || PropertyIvarDecl); } @@ -1457,7 +1465,21 @@ public: return PropertyIvarDecl; } void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; } + + Expr *getGetterCXXConstructor() const { + return GetterCXXConstructor; + } + void setGetterCXXConstructor(Expr *getterCXXConstructor) { + GetterCXXConstructor = getterCXXConstructor; + } + Expr *getSetterCXXAssignment() const { + return SetterCXXAssignment; + } + void setSetterCXXAssignment(Expr *setterCXXAssignment) { + SetterCXXAssignment = setterCXXAssignment; + } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCPropertyImplDecl *D) { return true; } static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; } diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 1ec38bacb51f..b7b90b14adfd 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -112,7 +112,7 @@ class TemplateArgumentListBuilder { unsigned MaxStructuredArgs; unsigned NumStructuredArgs; - TemplateArgument *FlatArgs; + llvm::SmallVector<TemplateArgument, 4> FlatArgs; unsigned MaxFlatArgs; unsigned NumFlatArgs; @@ -127,18 +127,12 @@ public: MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0), AddingToPack(false), PackBeginIndex(0) { } - void Append(const TemplateArgument& Arg); + void Append(const TemplateArgument &Arg); void BeginPack(); void EndPack(); - void ReleaseArgs(); - - unsigned flatSize() const { - return NumFlatArgs; - } - const TemplateArgument *getFlatArguments() const { - return FlatArgs; - } + unsigned flatSize() const { return FlatArgs.size(); } + const TemplateArgument *getFlatArguments() const { return FlatArgs.data(); } unsigned structuredSize() const { // If we don't have any structured args, just reuse the flat size. @@ -165,7 +159,7 @@ class TemplateArgumentList { /// \brief The template argument list. /// /// The integer value will be non-zero to indicate that this - /// template argument list does not own the pointer. + /// template argument list does own the pointer. llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments; /// \brief The number of template arguments in this template @@ -175,14 +169,28 @@ class TemplateArgumentList { llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments; unsigned NumStructuredArguments; + TemplateArgumentList(const TemplateArgumentList &Other); // DO NOT IMPL + void operator=(const TemplateArgumentList &Other); // DO NOT IMPL public: + /// TemplateArgumentList - If this constructor is passed "true" for 'TakeArgs' + /// it copies them into a locally new[]'d array. If passed "false", then it + /// just references the array passed in. This is only safe if the builder + /// outlives it, but saves a copy. TemplateArgumentList(ASTContext &Context, TemplateArgumentListBuilder &Builder, bool TakeArgs); - /// \brief Produces a shallow copy of the given template argument list - TemplateArgumentList(const TemplateArgumentList &Other); + /// Produces a shallow copy of the given template argument list. This + /// assumes that the input argument list outlives it. This takes the list as + /// a pointer to avoid looking like a copy constructor, since this really + /// really isn't safe to use that way. + explicit TemplateArgumentList(const TemplateArgumentList *Other); + /// Used to release the memory associated with a TemplateArgumentList + /// object. FIXME: This is currently not called anywhere, but the + /// memory will still be freed when using a BumpPtrAllocator. + void Destroy(ASTContext &C); + ~TemplateArgumentList(); /// \brief Retrieve the template argument at a given index. @@ -280,6 +288,9 @@ public: /// specialization from the function template. const TemplateArgumentList *TemplateArguments; + /// \brief The template arguments as written in the sources, if provided. + const TemplateArgumentListInfo *TemplateArgumentsAsWritten; + /// \brief The point at which this function template specialization was /// first instantiated. SourceLocation PointOfInstantiation; @@ -454,6 +465,8 @@ public: /// Declaration of a template function. class FunctionTemplateDecl : public TemplateDecl { + static void DeallocateCommon(void *Ptr); + protected: /// \brief Data that is common to all of the declarations of a given /// function template. @@ -862,7 +875,7 @@ class ClassTemplateSpecializationDecl unsigned SpecializationKind : 3; protected: - ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, + ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, @@ -870,7 +883,7 @@ protected: public: static ClassTemplateSpecializationDecl * - Create(ASTContext &Context, DeclContext *DC, SourceLocation L, + Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, ClassTemplateSpecializationDecl *PrevDecl); @@ -1024,7 +1037,7 @@ class ClassTemplatePartialSpecializationDecl llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool> InstantiatedFromMember; - ClassTemplatePartialSpecializationDecl(ASTContext &Context, + ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, @@ -1035,7 +1048,7 @@ class ClassTemplatePartialSpecializationDecl unsigned SequenceNumber) : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, - DC, L, SpecializedTemplate, Builder, + TK, DC, L, SpecializedTemplate, Builder, PrevDecl), TemplateParams(Params), ArgsAsWritten(ArgInfos), NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), @@ -1043,7 +1056,7 @@ class ClassTemplatePartialSpecializationDecl public: static ClassTemplatePartialSpecializationDecl * - Create(ASTContext &Context, DeclContext *DC, SourceLocation L, + Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, @@ -1158,6 +1171,8 @@ public: /// Declaration of a class template. class ClassTemplateDecl : public TemplateDecl { + static void DeallocateCommon(void *Ptr); + protected: /// \brief Data that is common to all of the declarations of a given /// class template. diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index 94017865d4c6..8a771d513c42 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -314,15 +314,16 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) { /// retrieved using its member functions (e.g., /// getCXXConstructorName). class DeclarationNameTable { + ASTContext &Ctx; void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> * CXXOperatorIdName *CXXOperatorNames; // Operator names - void *CXXLiteralOperatorNames; // Actually a FoldingSet<...> * + void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName* DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE public: - DeclarationNameTable(); + DeclarationNameTable(ASTContext &C); ~DeclarationNameTable(); /// getIdentifier - Create a declaration name that is a simple diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 2946e464a7cf..66639e2ef733 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -51,6 +51,7 @@ typedef UsuallyTinyPtrVector<const CXXBaseSpecifier> CXXBaseSpecifierArray; class Expr : public Stmt { QualType TR; + virtual void ANCHOR(); // key function. protected: /// TypeDependent - Whether this expression is type-dependent /// (C++ [temp.dep.expr]). @@ -247,6 +248,15 @@ public: SourceLocation DiagLoc; EvalResult() : HasSideEffects(false), Diag(0), DiagExpr(0) {} + + // isGlobalLValue - Return true if the evaluated lvalue expression + // is global. + bool isGlobalLValue() const; + // hasSideEffects - Return true if the evaluated expression has + // side effects. + bool hasSideEffects() const { + return HasSideEffects; + } }; /// Evaluate - Return true if this is a constant which we can fold using @@ -255,10 +265,6 @@ public: /// in Result. bool Evaluate(EvalResult &Result, ASTContext &Ctx) const; - /// EvaluateAsAny - The same as Evaluate, except that it also succeeds on - /// stack based objects. - bool EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const; - /// EvaluateAsBooleanCondition - Return true if this is a constant /// which we we can fold and convert to a boolean condition using /// any crazy technique that we want to. @@ -282,8 +288,7 @@ public: /// with link time known address. bool EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const; - /// EvaluateAsAnyLValue - The same as EvaluateAsLValue, except that it - /// also succeeds on stack based, immutable address lvalues. + /// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue. bool EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const; /// \brief Enumeration used to describe how \c isNullPointerConstant() @@ -321,6 +326,10 @@ public: /// or CastExprs, returning their operand. Expr *IgnoreParenCasts(); + /// IgnoreParenImpCasts - Ignore parentheses and implicit casts. Strip off any + /// ParenExpr or ImplicitCastExprs, returning their operand. + Expr *IgnoreParenImpCasts(); + /// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the /// value (including ptr->int casts of the same size). Strip off any /// ParenExpr or CastExprs, returning their operand. @@ -1468,13 +1477,10 @@ public: } static bool classof(const Stmt *T) { - return T->getStmtClass() == CallExprClass || - T->getStmtClass() == CXXOperatorCallExprClass || - T->getStmtClass() == CXXMemberCallExprClass; + return T->getStmtClass() >= firstCallExprConstant && + T->getStmtClass() <= lastCallExprConstant; } static bool classof(const CallExpr *) { return true; } - static bool classof(const CXXOperatorCallExpr *) { return true; } - static bool classof(const CXXMemberCallExpr *) { return true; } // Iterators virtual child_iterator child_begin(); @@ -1933,14 +1939,8 @@ public: const CXXBaseSpecifierArray& getBasePath() const { return BasePath; } static bool classof(const Stmt *T) { - StmtClass SC = T->getStmtClass(); - if (SC >= CXXStaticCastExprClass && SC <= CXXFunctionalCastExprClass) - return true; - - if (SC >= ImplicitCastExprClass && SC <= CStyleCastExprClass) - return true; - - return false; + return T->getStmtClass() >= firstCastExprConstant && + T->getStmtClass() <= lastCastExprConstant; } static bool classof(const CastExpr *) { return true; } @@ -2037,13 +2037,8 @@ public: QualType getTypeAsWritten() const { return TInfo->getType(); } static bool classof(const Stmt *T) { - StmtClass SC = T->getStmtClass(); - if (SC >= CStyleCastExprClass && SC <= CStyleCastExprClass) - return true; - if (SC >= CXXStaticCastExprClass && SC <= CXXFunctionalCastExprClass) - return true; - - return false; + return T->getStmtClass() >= firstExplicitCastExprConstant && + T->getStmtClass() <= lastExplicitCastExprConstant; } static bool classof(const ExplicitCastExpr *) { return true; } }; @@ -2198,8 +2193,8 @@ public: bool isShiftAssignOp() const { return Opc == ShlAssign || Opc == ShrAssign; } static bool classof(const Stmt *S) { - return S->getStmtClass() == BinaryOperatorClass || - S->getStmtClass() == CompoundAssignOperatorClass; + return S->getStmtClass() >= firstBinaryOperatorConstant && + S->getStmtClass() <= lastBinaryOperatorConstant; } static bool classof(const BinaryOperator *) { return true; } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index f9ca78ad292d..0c493f36df09 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -88,10 +88,13 @@ public: /// the object argument). class CXXMemberCallExpr : public CallExpr { public: - CXXMemberCallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, + CXXMemberCallExpr(ASTContext &C, Expr *fn, Expr **args, unsigned numargs, QualType t, SourceLocation rparenloc) : CallExpr(C, CXXMemberCallExprClass, fn, args, numargs, t, rparenloc) {} + CXXMemberCallExpr(ASTContext &C, EmptyShell Empty) + : CallExpr(C, CXXMemberCallExprClass, Empty) { } + /// getImplicitObjectArgument - Retrieves the implicit object /// argument for the member call. For example, in "x.f(5)", this /// operation would return "x". @@ -318,6 +321,14 @@ public: Operand->isTypeDependent() || Operand->isValueDependent()), Operand(Operand), Range(R) { } + CXXTypeidExpr(EmptyShell Empty, bool isExpr) + : Expr(CXXTypeidExprClass, Empty) { + if (isExpr) + Operand = (Expr*)0; + else + Operand = (TypeSourceInfo*)0; + } + bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); } /// \brief Retrieves the type operand of this typeid() expression after @@ -329,15 +340,25 @@ public: assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); return Operand.get<TypeSourceInfo *>(); } + + void setTypeOperandSourceInfo(TypeSourceInfo *TSI) { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + Operand = TSI; + } - Expr* getExprOperand() const { + Expr *getExprOperand() const { assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)"); return static_cast<Expr*>(Operand.get<Stmt *>()); } - - virtual SourceRange getSourceRange() const { - return Range; + + void setExprOperand(Expr *E) { + assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)"); + Operand = E; } + + virtual SourceRange getSourceRange() const { return Range; } + void setSourceRange(SourceRange R) { Range = R; } + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXTypeidExprClass; } @@ -371,6 +392,11 @@ public: Type->isDependentType(), Type->isDependentType()), Loc(L), Implicit(isImplicit) { } + CXXThisExpr(EmptyShell Empty) : Expr(CXXThisExprClass, Empty) {} + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } bool isImplicit() const { return Implicit; } @@ -399,6 +425,8 @@ public: // can by null, if the optional expression to throw isn't present. CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l) : Expr(CXXThrowExprClass, Ty, false, false), Op(expr), ThrowLoc(l) {} + CXXThrowExpr(EmptyShell Empty) : Expr(CXXThrowExprClass, Empty) {} + const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); } Expr *getSubExpr() { return cast_or_null<Expr>(Op); } void setSubExpr(Expr *E) { Op = E; } @@ -448,8 +476,7 @@ protected: CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param, Expr *SubExpr) - : Expr(SC, SubExpr->getType(), false, false), Param(param, true), Loc(Loc) - { + : Expr(SC, SubExpr->getType(), false, false), Param(param, true), Loc(Loc) { *reinterpret_cast<Expr **>(this + 1) = SubExpr; } @@ -457,6 +484,9 @@ protected: virtual void DoDestroy(ASTContext &C); public: + CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {} + + // Param is the parameter whose default argument is used by this // expression. static CXXDefaultArgExpr *Create(ASTContext &C, SourceLocation Loc, @@ -475,6 +505,9 @@ public: const ParmVarDecl *getParam() const { return Param.getPointer(); } ParmVarDecl *getParam() { return Param.getPointer(); } + /// isExprStored - Return true if this expression owns the expression. + bool isExprStored() const { return Param.getInt(); } + // Retrieve the actual argument to the function call. const Expr *getExpr() const { if (Param.getInt()) @@ -486,10 +519,16 @@ public: return *reinterpret_cast<Expr **> (this + 1); return getParam()->getDefaultArg(); } + + void setExpr(Expr *E) { + Param.setInt(true); + Param.setPointer((ParmVarDecl*)E); + } /// \brief Retrieve the location where this default argument was actually /// used. SourceLocation getUsedLocation() const { return Loc; } + void setUsedLocation(SourceLocation L) { Loc = L; } virtual SourceRange getSourceRange() const { // Default argument expressions have no representation in the @@ -525,8 +564,20 @@ public: const CXXDestructorDecl *getDestructor() const { return Destructor; } }; -/// CXXBindTemporaryExpr - Represents binding an expression to a temporary, -/// so its destructor can be called later. +/// \brief Represents binding an expression to a temporary. +/// +/// This ensures the destructor is called for the temporary. It should only be +/// needed for non-POD, non-trivially destructable class types. For example: +/// +/// \code +/// struct S { +/// S() { } // User defined constructor makes S non-POD. +/// ~S() { } // User defined destructor makes it non-trivial. +/// }; +/// void test() { +/// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr. +/// } +/// \endcode class CXXBindTemporaryExpr : public Expr { CXXTemporary *Temp; @@ -541,11 +592,15 @@ protected: virtual void DoDestroy(ASTContext &C); public: + CXXBindTemporaryExpr(EmptyShell Empty) + : Expr(CXXBindTemporaryExprClass, Empty), Temp(0), SubExpr(0) {} + static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp, Expr* SubExpr); CXXTemporary *getTemporary() { return Temp; } const CXXTemporary *getTemporary() const { return Temp; } + void setTemporary(CXXTemporary *T) { Temp = T; } const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } Expr *getSubExpr() { return cast<Expr>(SubExpr); } @@ -572,8 +627,8 @@ public: /// const int &i = 10; /// /// a bind reference expression is inserted to indicate that 10 is bound to -/// a reference. (Ans also that a temporary needs to be created to hold the -/// value). +/// a reference, and that a temporary needs to be created to hold the +/// value. class CXXBindReferenceExpr : public Expr { // SubExpr - The expression being bound. Stmt *SubExpr; @@ -827,10 +882,15 @@ public: SourceLocation rParenLoc ) : Expr(CXXZeroInitValueExprClass, ty, false, false), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} + explicit CXXZeroInitValueExpr(EmptyShell Shell) + : Expr(CXXZeroInitValueExprClass, Shell) { } SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } + void setTypeBeginLoc(SourceLocation L) { TyBeginLoc = L; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + /// @brief Whether this initialization expression was /// implicitly-generated. bool isImplicit() const { @@ -891,6 +951,11 @@ public: Expr **constructorArgs, unsigned numConsArgs, FunctionDecl *operatorDelete, QualType ty, SourceLocation startLoc, SourceLocation endLoc); + explicit CXXNewExpr(EmptyShell Shell) + : Expr(CXXNewExprClass, Shell), SubExprs(0) { } + + void AllocateArgsArray(ASTContext &C, bool isArray, unsigned numPlaceArgs, + unsigned numConsArgs); virtual void DoDestroy(ASTContext &C); @@ -900,8 +965,11 @@ public: } FunctionDecl *getOperatorNew() const { return OperatorNew; } + void setOperatorNew(FunctionDecl *D) { OperatorNew = D; } FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; } CXXConstructorDecl *getConstructor() const { return Constructor; } + void setConstructor(CXXConstructorDecl *D) { Constructor = D; } bool isArray() const { return Array; } Expr *getArraySize() { @@ -922,8 +990,11 @@ public: } bool isGlobalNew() const { return GlobalNew; } + void setGlobalNew(bool V) { GlobalNew = V; } bool isParenTypeId() const { return ParenTypeId; } + void setParenTypeId(bool V) { ParenTypeId = V; } bool hasInitializer() const { return Initializer; } + void setHasInitializer(bool V) { Initializer = V; } unsigned getNumConstructorArgs() const { return NumConstructorArgs; } Expr *getConstructorArg(unsigned i) { @@ -963,7 +1034,21 @@ public: const_arg_iterator constructor_arg_end() const { return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs(); } + + typedef Stmt **raw_arg_iterator; + raw_arg_iterator raw_arg_begin() { return SubExprs; } + raw_arg_iterator raw_arg_end() { + return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs(); + } + const_arg_iterator raw_arg_begin() const { return SubExprs; } + const_arg_iterator raw_arg_end() const { return constructor_arg_end(); } + + SourceLocation getStartLoc() const { return StartLoc; } + void setStartLoc(SourceLocation L) { StartLoc = L; } + SourceLocation getEndLoc() const { return EndLoc; } + void setEndLoc(SourceLocation L) { EndLoc = L; } + virtual SourceRange getSourceRange() const { return SourceRange(StartLoc, EndLoc); } @@ -1260,7 +1345,9 @@ class OverloadExpr : public Expr { /// The results. These are undesugared, which is to say, they may /// include UsingShadowDecls. Access is relative to the naming /// class. - UnresolvedSet<4> Results; + // FIXME: Allocate this data after the OverloadExpr subclass. + DeclAccessPair *Results; + unsigned NumResults; /// The common name of these declarations. DeclarationName Name; @@ -1278,14 +1365,11 @@ class OverloadExpr : public Expr { bool HasExplicitTemplateArgs; protected: - OverloadExpr(StmtClass K, QualType T, bool Dependent, + OverloadExpr(StmtClass K, ASTContext &C, QualType T, bool Dependent, NestedNameSpecifier *Qualifier, SourceRange QRange, DeclarationName Name, SourceLocation NameLoc, - bool HasTemplateArgs) - : Expr(K, T, Dependent, Dependent), - Name(Name), Qualifier(Qualifier), QualifierRange(QRange), - NameLoc(NameLoc), HasExplicitTemplateArgs(HasTemplateArgs) - {} + bool HasTemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End); public: /// Computes whether an unresolved lookup on the given declarations @@ -1309,22 +1393,17 @@ public: return llvm::PointerIntPair<OverloadExpr*,1>(cast<OverloadExpr>(E), op); } - void addDecls(UnresolvedSetIterator Begin, UnresolvedSetIterator End) { - Results.append(Begin, End); - } - /// Gets the naming class of this lookup, if any. CXXRecordDecl *getNamingClass() const; typedef UnresolvedSetImpl::iterator decls_iterator; - decls_iterator decls_begin() const { return Results.begin(); } - decls_iterator decls_end() const { return Results.end(); } - - /// Gets the decls as an unresolved set. - const UnresolvedSetImpl &getDecls() { return Results; } + decls_iterator decls_begin() const { return UnresolvedSetIterator(Results); } + decls_iterator decls_end() const { + return UnresolvedSetIterator(Results + NumResults); + } /// Gets the number of declarations in the unresolved set. - unsigned getNumDecls() const { return Results.size(); } + unsigned getNumDecls() const { return NumResults; } /// Gets the name looked up. DeclarationName getName() const { return Name; } @@ -1390,12 +1469,14 @@ class UnresolvedLookupExpr : public OverloadExpr { /// against the qualified-lookup bits. CXXRecordDecl *NamingClass; - UnresolvedLookupExpr(QualType T, bool Dependent, CXXRecordDecl *NamingClass, + UnresolvedLookupExpr(ASTContext &C, QualType T, bool Dependent, + CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QRange, DeclarationName Name, SourceLocation NameLoc, - bool RequiresADL, bool Overloaded, bool HasTemplateArgs) - : OverloadExpr(UnresolvedLookupExprClass, T, Dependent, Qualifier, QRange, - Name, NameLoc, HasTemplateArgs), + bool RequiresADL, bool Overloaded, bool HasTemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End) + : OverloadExpr(UnresolvedLookupExprClass, C, T, Dependent, Qualifier, + QRange, Name, NameLoc, HasTemplateArgs, Begin, End), RequiresADL(RequiresADL), Overloaded(Overloaded), NamingClass(NamingClass) {} @@ -1407,11 +1488,15 @@ public: SourceRange QualifierRange, DeclarationName Name, SourceLocation NameLoc, - bool ADL, bool Overloaded) { - return new(C) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, + bool ADL, bool Overloaded, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) { + return new(C) UnresolvedLookupExpr(C, + Dependent ? C.DependentTy : C.OverloadTy, Dependent, NamingClass, Qualifier, QualifierRange, - Name, NameLoc, ADL, Overloaded, false); + Name, NameLoc, ADL, Overloaded, false, + Begin, End); } static UnresolvedLookupExpr *Create(ASTContext &C, @@ -1422,7 +1507,9 @@ public: DeclarationName Name, SourceLocation NameLoc, bool ADL, - const TemplateArgumentListInfo &Args); + const TemplateArgumentListInfo &Args, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End); /// True if this declaration should be extended by /// argument-dependent lookup. @@ -1611,7 +1698,7 @@ class CXXExprWithTemporaries : public Expr { CXXTemporary **Temps; unsigned NumTemps; - CXXExprWithTemporaries(Expr *SubExpr, CXXTemporary **Temps, + CXXExprWithTemporaries(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, unsigned NumTemps); ~CXXExprWithTemporaries(); @@ -1619,11 +1706,17 @@ protected: virtual void DoDestroy(ASTContext &C); public: + CXXExprWithTemporaries(EmptyShell Empty) + : Expr(CXXExprWithTemporariesClass, Empty), + SubExpr(0), Temps(0), NumTemps(0) {} + static CXXExprWithTemporaries *Create(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, unsigned NumTemps); unsigned getNumTemporaries() const { return NumTemps; } + void setNumTemporaries(ASTContext &C, unsigned N); + CXXTemporary *getTemporary(unsigned i) { assert(i < NumTemps && "Index out of range"); return Temps[i]; @@ -1631,6 +1724,10 @@ public: const CXXTemporary *getTemporary(unsigned i) const { return const_cast<CXXExprWithTemporaries*>(this)->getTemporary(i); } + void setTemporary(unsigned i, CXXTemporary *T) { + assert(i < NumTemps && "Index out of range"); + Temps[i] = T; + } Expr *getSubExpr() { return cast<Expr>(SubExpr); } const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } @@ -2020,7 +2117,7 @@ class UnresolvedMemberExpr : public OverloadExpr { /// \brief The location of the '->' or '.' operator. SourceLocation OperatorLoc; - UnresolvedMemberExpr(QualType T, bool Dependent, + UnresolvedMemberExpr(ASTContext &C, QualType T, bool Dependent, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, @@ -2028,7 +2125,8 @@ class UnresolvedMemberExpr : public OverloadExpr { SourceRange QualifierRange, DeclarationName Member, SourceLocation MemberLoc, - const TemplateArgumentListInfo *TemplateArgs); + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End); public: static UnresolvedMemberExpr * @@ -2039,7 +2137,8 @@ public: SourceRange QualifierRange, DeclarationName Member, SourceLocation MemberLoc, - const TemplateArgumentListInfo *TemplateArgs); + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End); /// \brief True if this is an implicit access, i.e. one in which the /// member being accessed was not written in the source. The source diff --git a/include/clang/AST/Makefile b/include/clang/AST/Makefile new file mode 100644 index 000000000000..a25977cad621 --- /dev/null +++ b/include/clang/AST/Makefile @@ -0,0 +1,13 @@ +LEVEL = ../../../../.. +BUILT_SOURCES = StmtNodes.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(LEVEL)/Makefile.common + +INPUT_TDS = $(PROJ_SRC_DIR)/StmtNodes.td + +$(ObjDir)/StmtNodes.inc.tmp : StmtNodes.td $(TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang statement node tables with tblgen" + $(Verb) $(TableGen) -gen-clang-stmt-nodes -o $(call SYSPATH, $@) $< + diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index e78476ef51bb..2b3229e8fae9 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -109,6 +109,11 @@ private: /// which is the alignment of the object without virtual bases. uint64_t NonVirtualAlign; + /// SizeOfLargestEmptySubobject - The size of the largest empty subobject + /// (either a base or a member). Will be zero if the class doesn't contain + /// any empty subobjects. + uint64_t SizeOfLargestEmptySubobject; + /// PrimaryBase - The primary base info for this record. PrimaryBaseInfo PrimaryBase; @@ -127,7 +132,6 @@ private: CXXRecordLayoutInfo *CXXInfo; friend class ASTContext; - friend class ASTRecordLayoutBuilder; ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignment, unsigned datasize, const uint64_t *fieldoffsets, @@ -139,7 +143,9 @@ private: uint64_t size, unsigned alignment, uint64_t datasize, const uint64_t *fieldoffsets, unsigned fieldcount, uint64_t nonvirtualsize, unsigned nonvirtualalign, - const PrimaryBaseInfo &PrimaryBase, + uint64_t SizeOfLargestEmptySubobject, + const CXXRecordDecl *PrimaryBase, + bool PrimaryBaseIsVirtual, const BaseOffsetsMapTy& BaseOffsets, const BaseOffsetsMapTy& VBaseOffsets); @@ -222,6 +228,11 @@ public: return CXXInfo->VBaseOffsets[VBase]; } + uint64_t getSizeOfLargestEmptySubobject() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->SizeOfLargestEmptySubobject; + } + primary_base_info_iterator primary_base_begin() const { assert(CXXInfo && "Record layout does not have C++ specific info!"); diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h new file mode 100644 index 000000000000..07865e0eb3f1 --- /dev/null +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -0,0 +1,768 @@ +//===--- RecursiveASTVisitor.h - Recursive AST Visitor ----------*- 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 RecursiveASTVisitor interface, which recursively +// traverses the entire AST. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_RECURSIVEASTVISITOR_H +#define LLVM_CLANG_AST_RECURSIVEASTVISITOR_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" + +namespace clang { + +#define DISPATCH(NAME, CLASS, Var) \ +return getDerived().Visit ## NAME(static_cast<CLASS*>(Var)) + +// We use preprocessor meta-programming to generate the Visit*() +// methods for all subclasses of Stmt, Decl, and Type. Some of the +// generated definitions, however, need to be customized. The +// meta-programming technique we use doesn't let us select which +// methods to generate. Therefore we have to generate ALL of them in +// a helper class RecursiveASTVisitorImpl, and override the ones we +// don't like in a child class RecursiveASTVisitor (C++ doesn't allow +// overriding a method in the same class). +// +// Do not use this class directly - use RecursiveASTVisitor instead. +template<typename Derived> +class RecursiveASTVisitorImpl { +public: + /// \brief Return a reference to the derived class. + Derived &getDerived() { return *static_cast<Derived*>(this); } + + /// \brief Recursively visit a statement or expression, by + /// dispatching to Visit*() based on the argument's dynamic type. + /// This is NOT meant to be overridden by a subclass. + /// + /// \returns true if the visitation was terminated early, false + /// otherwise (including when the argument is NULL). + bool Visit(Stmt *S); + + /// \brief Recursively visit a type, by dispatching to + /// Visit*Type() based on the argument's getTypeClass() property. + /// This is NOT meant to be overridden by a subclass. + /// + /// \returns true if the visitation was terminated early, false + /// otherwise (including when the argument is a Null type). + bool Visit(QualType T); + + /// \brief Recursively visit a declaration, by dispatching to + /// Visit*Decl() based on the argument's dynamic type. This is + /// NOT meant to be overridden by a subclass. + /// + /// \returns true if the visitation was terminated early, false + /// otherwise (including when the argument is NULL). + bool Visit(Decl *D); + + /// \brief Recursively visit a C++ nested-name-specifier. + /// + /// \returns true if the visitation was terminated early, false otherwise. + bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); + + /// \brief Recursively visit a template name. + /// + /// \returns true if the visitation was terminated early, false otherwise. + bool VisitTemplateName(TemplateName Template); + + /// \brief Recursively visit a template argument. + /// + /// \returns true if the visitation was terminated early, false otherwise. + bool VisitTemplateArgument(const TemplateArgument &Arg); + + /// \brief Recursively visit a set of template arguments. + /// + /// \returns true if the visitation was terminated early, false otherwise. + bool VisitTemplateArguments(const TemplateArgument *Args, unsigned NumArgs); + + // If the implementation chooses not to implement a certain visit method, fall + // back on VisitExpr or whatever else is the superclass. +#define STMT(CLASS, PARENT) \ +bool Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT, S); } +#include "clang/AST/StmtNodes.inc" + + // If the implementation doesn't implement binary operator methods, fall back + // on VisitBinaryOperator. +#define BINOP_FALLBACK(NAME) \ +bool VisitBin ## NAME(BinaryOperator *S) { \ +DISPATCH(BinaryOperator, BinaryOperator, S); \ +} + BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI) + BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem) + BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl) + BINOP_FALLBACK(Shr) + + BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE) + BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE) + BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or) + BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr) + + BINOP_FALLBACK(Assign) + BINOP_FALLBACK(Comma) +#undef BINOP_FALLBACK + + // If the implementation doesn't implement compound assignment operator + // methods, fall back on VisitCompoundAssignOperator. +#define CAO_FALLBACK(NAME) \ +bool VisitBin ## NAME(CompoundAssignOperator *S) { \ +DISPATCH(CompoundAssignOperator, CompoundAssignOperator, S); \ +} + CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign) + CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign) + CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign) + CAO_FALLBACK(XorAssign) +#undef CAO_FALLBACK + + // If the implementation doesn't implement unary operator methods, fall back + // on VisitUnaryOperator. +#define UNARYOP_FALLBACK(NAME) \ +bool VisitUnary ## NAME(UnaryOperator *S) { \ +DISPATCH(UnaryOperator, UnaryOperator, S); \ +} + UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec) + UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec) + UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref) + + UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus) + UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot) + UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag) + UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf) +#undef UNARYOP_FALLBACK + + /// \brief Basis for statement and expression visitation, which + /// visits all of the substatements and subexpressions. + /// + /// The relation between Visit(Stmt *S) and this method is that + /// the former dispatches to Visit*() based on S's dynamic type, + /// which forwards the call up the inheritance chain until + /// reaching VisitStmt(), which then calls Visit() on each + /// substatement/subexpression. + bool VisitStmt(Stmt *S); + + /// \brief Basis for type visitation, which by default does nothing. + /// + /// The relation between Visit(QualType T) and this method is + /// that the former dispatches to Visit*Type(), which forwards the + /// call up the inheritance chain until reaching VisitType(). + bool VisitType(Type *T); + +#define TYPE(Class, Base) \ + bool Visit##Class##Type(Class##Type *T); +#include "clang/AST/TypeNodes.def" + + /// \brief Basis for declaration and definition visitation, which + /// visits all of the subnodes. + /// + /// The relation between Visit(Decl *) and this method is that the + /// former dispatches to Visit*Decl(), which forwards the call up + /// the inheritance chain until reaching VisitDecl(). + bool VisitDecl(Decl *D); + +#define DECL(Class, Base) \ + bool Visit##Class##Decl(Class##Decl *D) { \ + return getDerived().Visit##Base(D); \ + } +#define ABSTRACT_DECL(Class, Base) DECL(Class, Base) +#include "clang/AST/DeclNodes.def" +}; + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::Visit(Stmt *S) { + if (!S) + return false; + + // If we have a binary expr, dispatch to the subcode of the binop. A smart + // optimizer (e.g. LLVM) will fold this comparison into the switch stmt + // below. + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { + switch (BinOp->getOpcode()) { + case BinaryOperator::PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator, S); + case BinaryOperator::PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator, S); + case BinaryOperator::Mul: DISPATCH(BinMul, BinaryOperator, S); + case BinaryOperator::Div: DISPATCH(BinDiv, BinaryOperator, S); + case BinaryOperator::Rem: DISPATCH(BinRem, BinaryOperator, S); + case BinaryOperator::Add: DISPATCH(BinAdd, BinaryOperator, S); + case BinaryOperator::Sub: DISPATCH(BinSub, BinaryOperator, S); + case BinaryOperator::Shl: DISPATCH(BinShl, BinaryOperator, S); + case BinaryOperator::Shr: DISPATCH(BinShr, BinaryOperator, S); + + case BinaryOperator::LT: DISPATCH(BinLT, BinaryOperator, S); + case BinaryOperator::GT: DISPATCH(BinGT, BinaryOperator, S); + case BinaryOperator::LE: DISPATCH(BinLE, BinaryOperator, S); + case BinaryOperator::GE: DISPATCH(BinGE, BinaryOperator, S); + case BinaryOperator::EQ: DISPATCH(BinEQ, BinaryOperator, S); + case BinaryOperator::NE: DISPATCH(BinNE, BinaryOperator, S); + + case BinaryOperator::And: DISPATCH(BinAnd, BinaryOperator, S); + case BinaryOperator::Xor: DISPATCH(BinXor, BinaryOperator, S); + case BinaryOperator::Or : DISPATCH(BinOr, BinaryOperator, S); + case BinaryOperator::LAnd: DISPATCH(BinLAnd, BinaryOperator, S); + case BinaryOperator::LOr : DISPATCH(BinLOr, BinaryOperator, S); + case BinaryOperator::Assign: DISPATCH(BinAssign, BinaryOperator, S); + case BinaryOperator::MulAssign: + DISPATCH(BinMulAssign, CompoundAssignOperator, S); + case BinaryOperator::DivAssign: + DISPATCH(BinDivAssign, CompoundAssignOperator, S); + case BinaryOperator::RemAssign: + DISPATCH(BinRemAssign, CompoundAssignOperator, S); + case BinaryOperator::AddAssign: + DISPATCH(BinAddAssign, CompoundAssignOperator, S); + case BinaryOperator::SubAssign: + DISPATCH(BinSubAssign, CompoundAssignOperator, S); + case BinaryOperator::ShlAssign: + DISPATCH(BinShlAssign, CompoundAssignOperator, S); + case BinaryOperator::ShrAssign: + DISPATCH(BinShrAssign, CompoundAssignOperator, S); + case BinaryOperator::AndAssign: + DISPATCH(BinAndAssign, CompoundAssignOperator, S); + case BinaryOperator::OrAssign: + DISPATCH(BinOrAssign, CompoundAssignOperator, S); + case BinaryOperator::XorAssign: + DISPATCH(BinXorAssign, CompoundAssignOperator, S); + case BinaryOperator::Comma: DISPATCH(BinComma, BinaryOperator, S); + } + } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) { + switch (UnOp->getOpcode()) { + case UnaryOperator::PostInc: DISPATCH(UnaryPostInc, UnaryOperator, S); + case UnaryOperator::PostDec: DISPATCH(UnaryPostDec, UnaryOperator, S); + case UnaryOperator::PreInc: DISPATCH(UnaryPreInc, UnaryOperator, S); + case UnaryOperator::PreDec: DISPATCH(UnaryPreDec, UnaryOperator, S); + case UnaryOperator::AddrOf: DISPATCH(UnaryAddrOf, UnaryOperator, S); + case UnaryOperator::Deref: DISPATCH(UnaryDeref, UnaryOperator, S); + case UnaryOperator::Plus: DISPATCH(UnaryPlus, UnaryOperator, S); + case UnaryOperator::Minus: DISPATCH(UnaryMinus, UnaryOperator, S); + case UnaryOperator::Not: DISPATCH(UnaryNot, UnaryOperator, S); + case UnaryOperator::LNot: DISPATCH(UnaryLNot, UnaryOperator, S); + case UnaryOperator::Real: DISPATCH(UnaryReal, UnaryOperator, S); + case UnaryOperator::Imag: DISPATCH(UnaryImag, UnaryOperator, S); + case UnaryOperator::Extension: DISPATCH(UnaryExtension, UnaryOperator, S); + case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator, S); + } + } + + // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: break; +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ +case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS, S); +#include "clang/AST/StmtNodes.inc" + } + + return false; +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::Visit(QualType T) { + if (T.isNull()) + return false; + + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Base) +#define TYPE(Class, Base) \ + case Type::Class: DISPATCH(Class##Type, Class##Type, T.getTypePtr()); +#include "clang/AST/TypeNodes.def" + } + + return false; +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::Visit(Decl *D) { + if (!D) + return false; + + switch (D->getKind()) { +#define ABSTRACT_DECL(Class, Base) +#define DECL(Class, Base) \ + case Decl::Class: DISPATCH(Class##Decl, Class##Decl, D); +#include "clang/AST/DeclNodes.def" + } + + return false; +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitNestedNameSpecifier( + NestedNameSpecifier *NNS) { + if (NNS->getPrefix() && + getDerived().VisitNestedNameSpecifier(NNS->getPrefix())) + return true; + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::Global: + return false; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + return Visit(QualType(NNS->getAsType(), 0)); + } + + return false; +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitTemplateName(TemplateName Template) { + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) + return DTN->getQualifier() && + getDerived().VisitNestedNameSpecifier(DTN->getQualifier()); + + if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + return getDerived().VisitNestedNameSpecifier(QTN->getQualifier()); + + return false; +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitTemplateArgument( + const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + return false; + + case TemplateArgument::Type: + return Visit(Arg.getAsType()); + + case TemplateArgument::Template: + return getDerived().VisitTemplateName(Arg.getAsTemplate()); + + case TemplateArgument::Expression: + return getDerived().Visit(Arg.getAsExpr()); + + case TemplateArgument::Pack: + return getDerived().VisitTemplateArguments(Arg.pack_begin(), + Arg.pack_size()); + } + + return false; +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitTemplateArguments( + const TemplateArgument *Args, + unsigned NumArgs) { + for (unsigned I = 0; I != NumArgs; ++I) + if (getDerived().VisitTemplateArgument(Args[I])) + return true; + + return false; +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitStmt(Stmt *Node) { + for (Stmt::child_iterator C = Node->child_begin(), CEnd = Node->child_end(); + C != CEnd; ++C) { + if (Visit(*C)) + return true; + } + + return false; +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitType(Type *T) { + return false; +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitBuiltinType(BuiltinType *T) { + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitComplexType(ComplexType *T) { + if (Visit(T->getElementType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitPointerType(PointerType *T) { + if (Visit(T->getPointeeType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitBlockPointerType( + BlockPointerType *T) { + if (Visit(T->getPointeeType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitReferenceType(ReferenceType *T) { + if (Visit(T->getPointeeType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitLValueReferenceType( + LValueReferenceType *T) { + return getDerived().VisitReferenceType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitRValueReferenceType( + RValueReferenceType *T) { + return getDerived().VisitReferenceType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitMemberPointerType( + MemberPointerType *T) { + if (Visit(QualType(T->getClass(), 0)) || Visit(T->getPointeeType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitArrayType(ArrayType *T) { + if (Visit(T->getElementType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitConstantArrayType( + ConstantArrayType *T) { + return getDerived().VisitArrayType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitIncompleteArrayType( + IncompleteArrayType *T) { + return getDerived().VisitArrayType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitVariableArrayType( + VariableArrayType *T) { + if (Visit(T->getSizeExpr())) + return true; + + return getDerived().VisitArrayType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitDependentSizedArrayType( + DependentSizedArrayType *T) { + if (T->getSizeExpr() && Visit(T->getSizeExpr())) + return true; + + return getDerived().VisitArrayType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitDependentSizedExtVectorType( + DependentSizedExtVectorType *T) { + if ((T->getSizeExpr() && Visit(T->getSizeExpr())) || + Visit(T->getElementType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitVectorType(VectorType *T) { + if (Visit(T->getElementType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitExtVectorType(ExtVectorType *T) { + return getDerived().VisitVectorType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitFunctionType(FunctionType *T) { + if (Visit(T->getResultType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitFunctionNoProtoType( + FunctionNoProtoType *T) { + return getDerived().VisitFunctionType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitFunctionProtoType( + FunctionProtoType *T) { + for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), + AEnd = T->arg_type_end(); + A != AEnd; ++A) { + if (Visit(*A)) + return true; + } + + for (FunctionProtoType::exception_iterator E = T->exception_begin(), + EEnd = T->exception_end(); + E != EEnd; ++E) { + if (Visit(*E)) + return true; + } + + return getDerived().VisitFunctionType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitUnresolvedUsingType( + UnresolvedUsingType *T) { + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitTypedefType(TypedefType *T) { + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitTypeOfExprType(TypeOfExprType *T) { + if (Visit(T->getUnderlyingExpr())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitTypeOfType(TypeOfType *T) { + if (Visit(T->getUnderlyingType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitDecltypeType(DecltypeType *T) { + if (Visit(T->getUnderlyingExpr())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitTagType(TagType *T) { + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitRecordType(RecordType *T) { + return getDerived().VisitTagType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitEnumType(EnumType *T) { + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitTemplateTypeParmType( + TemplateTypeParmType *T) { + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitSubstTemplateTypeParmType( + SubstTemplateTypeParmType *T) { + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitTemplateSpecializationType( + TemplateSpecializationType *T) { + if (getDerived().VisitTemplateName(T->getTemplateName()) || + getDerived().VisitTemplateArguments(T->getArgs(), T->getNumArgs())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitInjectedClassNameType( + InjectedClassNameType *T) { + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitElaboratedType(ElaboratedType *T) { + if (T->getQualifier() && + getDerived().VisitNestedNameSpecifier(T->getQualifier())) + return true; + if (Visit(T->getNamedType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitDependentNameType( + DependentNameType *T) { + if (T->getQualifier() && + getDerived().VisitNestedNameSpecifier(T->getQualifier())) + return true; + + if (T->getTemplateId() && + getDerived().VisitTemplateSpecializationType( + const_cast<TemplateSpecializationType *>(T->getTemplateId()))) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitObjCInterfaceType( + ObjCInterfaceType *T) { + return getDerived().VisitObjCObjectType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitObjCObjectType(ObjCObjectType *T) { + // We have to watch out here because an ObjCInterfaceType's base + // type is itself. + if (T->getBaseType().getTypePtr() != T) + if (Visit(T->getBaseType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitObjCObjectPointerType( + ObjCObjectPointerType *T) { + if (Visit(T->getPointeeType())) + return true; + + return getDerived().VisitType(T); +} + +template<typename Derived> +bool RecursiveASTVisitorImpl<Derived>::VisitDecl(Decl *D) { + if (DeclContext *DC = dyn_cast<DeclContext>(D)) { + for (DeclContext::decl_iterator Child = DC->decls_begin(), + ChildEnd = DC->decls_end(); + Child != ChildEnd; ++Child) + if (Visit(*Child)) + return true; + + return false; + } + + return false; +} + +/// \brief A visitor that recursively walks the entire Clang AST. +/// +/// Clients of this visitor should subclass the visitor (providing +/// themselves as the template argument, using the curiously +/// recurring template pattern) and override any of the Visit* +/// methods (except Visit()) for declaration, type, statement, +/// expression, or other AST nodes where the visitor should customize +/// behavior. Returning "true" from one of these overridden functions +/// will abort the entire traversal. An overridden Visit* method +/// will not descend further into the AST for that node unless +/// Base::Visit* is called. +template<typename Derived> +class RecursiveASTVisitor : public RecursiveASTVisitorImpl<Derived> { + typedef RecursiveASTVisitorImpl<Derived> Impl; +public: + typedef RecursiveASTVisitor<Derived> Base; + + bool VisitDeclaratorDecl(DeclaratorDecl *D); + bool VisitFunctionDecl(FunctionDecl *D); + bool VisitVarDecl(VarDecl *D); + bool VisitBlockDecl(BlockDecl *D); + bool VisitDeclStmt(DeclStmt *S); + bool VisitFunctionType(FunctionType *F); + bool VisitFunctionProtoType(FunctionProtoType *F); +}; + +#define DEFINE_VISIT(Type, Name, Statement) \ + template<typename Derived> \ + bool RecursiveASTVisitor<Derived>::Visit ## Type (Type *Name) { \ + if (Impl::Visit ## Type (Name)) return true; \ + { Statement; } \ + return false; \ + } + +DEFINE_VISIT(DeclaratorDecl, D, { + if (TypeSourceInfo *TInfo = D->getTypeSourceInfo()) + return this->Visit(TInfo->getType()); + }) + +DEFINE_VISIT(FunctionDecl, D, { + if (D->isThisDeclarationADefinition()) + return this->Visit(D->getBody()); + }) + +DEFINE_VISIT(VarDecl, D, return this->Visit(D->getInit())) + +DEFINE_VISIT(BlockDecl, D, return this->Visit(D->getBody())) + +DEFINE_VISIT(DeclStmt, S, { + for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end(); + I != E; ++I) { + if (this->Visit(*I)) + return true; + } + }) + +// FunctionType is the common base class of FunctionNoProtoType (a +// K&R-style function declaration that has no information about +// its arguments) and FunctionProtoType. +DEFINE_VISIT(FunctionType, F, return this->Visit(F->getResultType())) + +DEFINE_VISIT(FunctionProtoType, F, { + for (unsigned i = 0; i != F->getNumArgs(); ++i) { + if (this->Visit(F->getArgType(i))) + return true; + } + for (unsigned i = 0; i != F->getNumExceptions(); ++i) { + if (this->Visit(F->getExceptionType(i))) + return true; + } + }) + +#undef DEFINE_VISIT + +#undef DISPATCH + +} // end namespace clang + +#endif // LLVM_CLANG_AST_RECURSIVEASTVISITOR_H diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 0b68a4007363..9deae1561586 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -98,12 +98,14 @@ public: enum StmtClass { NoStmtClass = 0, #define STMT(CLASS, PARENT) CLASS##Class, -#define FIRST_STMT(CLASS) firstStmtConstant = CLASS##Class, -#define LAST_STMT(CLASS) lastStmtConstant = CLASS##Class, -#define FIRST_EXPR(CLASS) firstExprConstant = CLASS##Class, -#define LAST_EXPR(CLASS) lastExprConstant = CLASS##Class -#define ABSTRACT_EXPR(CLASS, PARENT) -#include "clang/AST/StmtNodes.def" +#define STMT_RANGE(BASE, FIRST, LAST) \ + first##BASE##Constant = FIRST##Class, \ + last##BASE##Constant = LAST##Class, +#define LAST_STMT_RANGE(BASE, FIRST, LAST) \ + first##BASE##Constant = FIRST##Class, \ + last##BASE##Constant = LAST##Class +#define ABSTRACT_STMT(STMT) +#include "clang/AST/StmtNodes.inc" }; private: /// \brief The statement class. @@ -1083,9 +1085,15 @@ public: class ReturnStmt : public Stmt { Stmt *RetExpr; SourceLocation RetLoc; + const VarDecl *NRVOCandidate; + public: - ReturnStmt(SourceLocation RL, Expr *E = 0) : Stmt(ReturnStmtClass), - RetExpr((Stmt*) E), RetLoc(RL) {} + ReturnStmt(SourceLocation RL) + : Stmt(ReturnStmtClass), RetExpr(0), RetLoc(RL), NRVOCandidate(0) { } + + ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate) + : Stmt(ReturnStmtClass), RetExpr((Stmt*) E), RetLoc(RL), + NRVOCandidate(NRVOCandidate) {} /// \brief Build an empty return expression. explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { } @@ -1097,6 +1105,14 @@ public: SourceLocation getReturnLoc() const { return RetLoc; } void setReturnLoc(SourceLocation L) { RetLoc = L; } + /// \brief Retrieve the variable that might be used for the named return + /// value optimization. + /// + /// The optimization itself can only be performed if the variable is + /// also marked as an NRVO object. + const VarDecl *getNRVOCandidate() const { return NRVOCandidate; } + void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; } + virtual SourceRange getSourceRange() const; static bool classof(const Stmt *T) { diff --git a/include/clang/AST/StmtNodes.td b/include/clang/AST/StmtNodes.td new file mode 100644 index 000000000000..60c94a609b4a --- /dev/null +++ b/include/clang/AST/StmtNodes.td @@ -0,0 +1,127 @@ +class Stmt<bit abstract = 0> { + bit Abstract = abstract; +} + +class DStmt<Stmt base, bit abstract = 0> : Stmt<abstract> { + Stmt Base = base; +} + +// Statements +def NullStmt : Stmt; +def CompoundStmt : Stmt; +def LabelStmt : Stmt; +def IfStmt : Stmt; +def SwitchStmt : Stmt; +def WhileStmt : Stmt; +def DoStmt : Stmt; +def ForStmt : Stmt; +def GotoStmt : Stmt; +def IndirectGotoStmt : Stmt; +def ContinueStmt : Stmt; +def BreakStmt : Stmt; +def ReturnStmt : Stmt; +def DeclStmt : Stmt; +def SwitchCase : Stmt; +def CaseStmt : DStmt<SwitchCase>; +def DefaultStmt : DStmt<SwitchCase>; + +// GNU Extensions +def AsmStmt : Stmt; + +// Obj-C statements +def ObjCAtTryStmt : Stmt; +def ObjCAtCatchStmt : Stmt; +def ObjCAtFinallyStmt : Stmt; +def ObjCAtThrowStmt : Stmt; +def ObjCAtSynchronizedStmt : Stmt; +def ObjCForCollectionStmt : Stmt; + +// C++ statments +def CXXCatchStmt : Stmt; +def CXXTryStmt : Stmt; + +// Expressions +def Expr : Stmt<1>; +def PredefinedExpr : DStmt<Expr>; +def DeclRefExpr : DStmt<Expr>; +def IntegerLiteral : DStmt<Expr>; +def FloatingLiteral : DStmt<Expr>; +def ImaginaryLiteral : DStmt<Expr>; +def StringLiteral : DStmt<Expr>; +def CharacterLiteral : DStmt<Expr>; +def ParenExpr : DStmt<Expr>; +def UnaryOperator : DStmt<Expr>; +def OffsetOfExpr : DStmt<Expr>; +def SizeOfAlignOfExpr : DStmt<Expr>; +def ArraySubscriptExpr : DStmt<Expr>; +def CallExpr : DStmt<Expr>; +def MemberExpr : DStmt<Expr>; +def CastExpr : DStmt<Expr, 1>; +def BinaryOperator : DStmt<Expr>; +def CompoundAssignOperator : DStmt<BinaryOperator>; +def ConditionalOperator : DStmt<Expr>; +def ImplicitCastExpr : DStmt<CastExpr>; +def ExplicitCastExpr : DStmt<CastExpr, 1>; +def CStyleCastExpr : DStmt<ExplicitCastExpr>; +def CompoundLiteralExpr : DStmt<Expr>; +def ExtVectorElementExpr : DStmt<Expr>; +def InitListExpr : DStmt<Expr>; +def DesignatedInitExpr : DStmt<Expr>; +def ImplicitValueInitExpr : DStmt<Expr>; +def ParenListExpr : DStmt<Expr>; +def VAArgExpr : DStmt<Expr>; + +// GNU Extensions. +def AddrLabelExpr : DStmt<Expr>; +def StmtExpr : DStmt<Expr>; +def TypesCompatibleExpr : DStmt<Expr>; +def ChooseExpr : DStmt<Expr>; +def GNUNullExpr : DStmt<Expr>; + +// C++ Expressions. +def CXXOperatorCallExpr : DStmt<CallExpr>; +def CXXMemberCallExpr : DStmt<CallExpr>; +def CXXNamedCastExpr : DStmt<ExplicitCastExpr, 1>; +def CXXStaticCastExpr : DStmt<CXXNamedCastExpr>; +def CXXDynamicCastExpr : DStmt<CXXNamedCastExpr>; +def CXXReinterpretCastExpr : DStmt<CXXNamedCastExpr>; +def CXXConstCastExpr : DStmt<CXXNamedCastExpr>; +def CXXFunctionalCastExpr : DStmt<ExplicitCastExpr>; +def CXXTypeidExpr : DStmt<Expr>; +def CXXBoolLiteralExpr : DStmt<Expr>; +def CXXNullPtrLiteralExpr : DStmt<Expr>; +def CXXThisExpr : DStmt<Expr>; +def CXXThrowExpr : DStmt<Expr>; +def CXXDefaultArgExpr : DStmt<Expr>; +def CXXZeroInitValueExpr : DStmt<Expr>; +def CXXNewExpr : DStmt<Expr>; +def CXXDeleteExpr : DStmt<Expr>; +def CXXPseudoDestructorExpr : DStmt<Expr>; +def UnresolvedLookupExpr : DStmt<Expr>; +def UnaryTypeTraitExpr : DStmt<Expr>; +def DependentScopeDeclRefExpr : DStmt<Expr>; +def CXXConstructExpr : DStmt<Expr>; +def CXXBindTemporaryExpr : DStmt<Expr>; +def CXXBindReferenceExpr : DStmt<Expr>; +def CXXExprWithTemporaries : DStmt<Expr>; +def CXXTemporaryObjectExpr : DStmt<CXXConstructExpr>; +def CXXUnresolvedConstructExpr : DStmt<Expr>; +def CXXDependentScopeMemberExpr : DStmt<Expr>; +def UnresolvedMemberExpr : DStmt<Expr>; + +// Obj-C Expressions. +def ObjCStringLiteral : DStmt<Expr>; +def ObjCEncodeExpr : DStmt<Expr>; +def ObjCMessageExpr : DStmt<Expr>; +def ObjCSelectorExpr : DStmt<Expr>; +def ObjCProtocolExpr : DStmt<Expr>; +def ObjCIvarRefExpr : DStmt<Expr>; +def ObjCPropertyRefExpr : DStmt<Expr>; +def ObjCImplicitSetterGetterRefExpr : DStmt<Expr>; +def ObjCSuperExpr : DStmt<Expr>; +def ObjCIsaExpr : DStmt<Expr>; + +// Clang Extensions. +def ShuffleVectorExpr : DStmt<Expr>; +def BlockExpr : DStmt<Expr>; +def BlockDeclRefExpr : DStmt<Expr>; diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h index 4986f08ac124..8078451fa31f 100644 --- a/include/clang/AST/StmtVisitor.h +++ b/include/clang/AST/StmtVisitor.h @@ -105,10 +105,10 @@ public: // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. switch (S->getStmtClass()) { default: assert(0 && "Unknown stmt kind!"); -#define ABSTRACT_EXPR(CLASS, PARENT) +#define ABSTRACT_STMT(STMT) #define STMT(CLASS, PARENT) \ case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS); -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" } } @@ -116,7 +116,7 @@ public: // back on VisitExpr or whatever else is the superclass. #define STMT(CLASS, PARENT) \ RetTy Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT); } -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" // If the implementation doesn't implement binary operator methods, fall back // on VisitBinaryOperator. diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index 50a100c6af13..8b38001bd104 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -28,6 +28,7 @@ namespace llvm { namespace clang { class Decl; +class DiagnosticBuilder; class Expr; class TypeSourceInfo; @@ -473,6 +474,9 @@ public: } }; -} +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const TemplateArgument &Arg); + +} // end namespace clang #endif diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index f3de9fa011bc..2e3b6df0549b 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -188,7 +188,7 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, /// declaration for "vector". The QualifiedTemplateName class is only /// used to provide "sugar" for template names that were expressed /// with a qualified name, and has no semantic meaning. In this -/// manner, it is to TemplateName what QualifiedNameType is to Type, +/// manner, it is to TemplateName what ElaboratedType is to Type, /// providing extra syntactic sugar for downstream clients. class QualifiedTemplateName : public llvm::FoldingSetNode { /// \brief The nested name specifier that qualifies the template name. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 030c74c64089..c24bddb30082 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -92,7 +92,7 @@ namespace clang { class TemplateArgumentLoc; class TemplateArgumentListInfo; class Type; - class QualifiedNameType; + class ElaboratedType; struct PrintingPolicy; template <typename> class CanQual; @@ -396,7 +396,8 @@ enum CallingConv { CC_Default, CC_C, // __attribute__((cdecl)) CC_X86StdCall, // __attribute__((stdcall)) - CC_X86FastCall // __attribute__((fastcall)) + CC_X86FastCall, // __attribute__((fastcall)) + CC_X86ThisCall // __attribute__((thiscall)) }; @@ -755,6 +756,9 @@ public: }; private: + Type(const Type&); // DO NOT IMPLEMENT. + void operator=(const Type&); // DO NOT IMPLEMENT. + QualType CanonicalType; /// TypeClass bitfield - Enum that specifies what subclass this belongs to. @@ -764,15 +768,25 @@ private: /// Note that this should stay at the end of the ivars for Type so that /// subclasses can pack their bitfields into the same word. bool Dependent : 1; - - Type(const Type&); // DO NOT IMPLEMENT. - void operator=(const Type&); // DO NOT IMPLEMENT. + + /// \brief Whether the linkage of this type is already known. + mutable bool LinkageKnown : 1; + + /// \brief Linkage of this type. + mutable unsigned CachedLinkage : 2; + protected: + /// \brief Compute the linkage of this type. + virtual Linkage getLinkageImpl() const; + + enum { BitsRemainingInType = 20 }; + // silence VC++ warning C4355: 'this' : used in base member initializer list Type *this_() { return this; } Type(TypeClass tc, QualType Canonical, bool dependent) : CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical), - TC(tc), Dependent(dependent) {} + TC(tc), Dependent(dependent), LinkageKnown(false), + CachedLinkage(NoLinkage) {} virtual ~Type() {} virtual void Destroy(ASTContext& C); friend class ASTContext; @@ -879,7 +893,7 @@ public: bool isObjCObjectPointerType() const; // Pointer to *any* ObjC object. // FIXME: change this to 'raw' interface type, so we can used 'interface' type // for the common case. - bool isObjCInterfaceType() const; // NSString or NSString<foo> + bool isObjCObjectType() const; // NSString or typeof(*(id)0) bool isObjCQualifiedInterfaceType() const; // NSString<foo> bool isObjCQualifiedIdType() const; // id<foo> bool isObjCQualifiedClassType() const; // Class<foo> @@ -920,7 +934,7 @@ public: // for object declared using an interface. const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; - const ObjCInterfaceType *getAsObjCQualifiedInterfaceType() const; + const ObjCObjectType *getAsObjCQualifiedInterfaceType() const; const CXXRecordDecl *getCXXRecordDeclForPointerType() const; /// \brief Retrieves the CXXRecordDecl that this type refers to, either @@ -935,10 +949,6 @@ public: // immediately following this class. template <typename T> const T *getAs() const; - /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC - /// interface, return the interface type, otherwise return null. - const ObjCInterfaceType *getAsPointerToObjCInterfaceType() const; - /// getArrayElementTypeNoTypeQual - If this is an array type, return the /// element type of the array, potentially with type qualifiers missing. /// This method should never be used when type qualifiers are meaningful. @@ -977,10 +987,13 @@ public: /// set of type specifiers. bool isSpecifierType() const; - const char *getTypeClassName() const; - /// \brief Determine the linkage of this type. - virtual Linkage getLinkage() const; + Linkage getLinkage() const; + + /// \brief Note that the linkage is no longer known. + void ClearLinkageCache(); + + const char *getTypeClassName() const; QualType getCanonicalTypeInternal() const { return CanonicalType; @@ -1040,12 +1053,25 @@ public: UndeducedAuto, // In C++0x, this represents the type of an auto variable // that has not been deduced yet. - ObjCId, // This represents the ObjC 'id' type. - ObjCClass, // This represents the ObjC 'Class' type. + + /// The primitive Objective C 'id' type. The type pointed to by the + /// user-visible 'id' type. Only ever shows up in an AST as the base + /// type of an ObjCObjectType. + ObjCId, + + /// The primitive Objective C 'Class' type. The type pointed to by the + /// user-visible 'Class' type. Only ever shows up in an AST as the + /// base type of an ObjCObjectType. + ObjCClass, + ObjCSel // This represents the ObjC 'SEL' type. }; private: Kind TypeKind; + +protected: + virtual Linkage getLinkageImpl() const; + public: BuiltinType(Kind K) : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)), @@ -1073,8 +1099,6 @@ public: return TypeKind >= Float && TypeKind <= LongDouble; } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } static bool classof(const BuiltinType *) { return true; } }; @@ -1089,6 +1113,10 @@ class ComplexType : public Type, public llvm::FoldingSetNode { ElementType(Element) { } friend class ASTContext; // ASTContext creates these. + +protected: + virtual Linkage getLinkageImpl() const; + public: QualType getElementType() const { return ElementType; } @@ -1102,8 +1130,6 @@ public: ID.AddPointer(Element.getAsOpaquePtr()); } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == Complex; } static bool classof(const ComplexType *) { return true; } }; @@ -1117,6 +1143,10 @@ class PointerType : public Type, public llvm::FoldingSetNode { Type(Pointer, CanonicalPtr, Pointee->isDependentType()), PointeeType(Pointee) { } friend class ASTContext; // ASTContext creates these. + +protected: + virtual Linkage getLinkageImpl() const; + public: QualType getPointeeType() const { return PointeeType; } @@ -1131,8 +1161,6 @@ public: ID.AddPointer(Pointee.getAsOpaquePtr()); } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } static bool classof(const PointerType *) { return true; } }; @@ -1148,6 +1176,10 @@ class BlockPointerType : public Type, public llvm::FoldingSetNode { PointeeType(Pointee) { } friend class ASTContext; // ASTContext creates these. + +protected: + virtual Linkage getLinkageImpl() const; + public: // Get the pointee type. Pointee is required to always be a function type. @@ -1163,8 +1195,6 @@ public: ID.AddPointer(Pointee.getAsOpaquePtr()); } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == BlockPointer; } @@ -1200,6 +1230,9 @@ protected: PointeeType(Referencee), SpelledAsLValue(SpelledAsLValue), InnerRef(Referencee->isReferenceType()) { } + + virtual Linkage getLinkageImpl() const; + public: bool isSpelledAsLValue() const { return SpelledAsLValue; } bool isInnerRef() const { return InnerRef; } @@ -1223,8 +1256,6 @@ public: ID.AddBoolean(SpelledAsLValue); } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == LValueReference || T->getTypeClass() == RValueReference; @@ -1281,6 +1312,10 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { PointeeType(Pointee), Class(Cls) { } friend class ASTContext; // ASTContext creates these. + +protected: + virtual Linkage getLinkageImpl() const; + public: QualType getPointeeType() const { return PointeeType; } @@ -1299,8 +1334,6 @@ public: ID.AddPointer(Class); } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == MemberPointer; } @@ -1342,6 +1375,9 @@ protected: ElementType(et), SizeModifier(sm), IndexTypeQuals(tq) {} friend class ASTContext; // ASTContext creates these. + + virtual Linkage getLinkageImpl() const; + public: QualType getElementType() const { return ElementType; } ArraySizeModifier getSizeModifier() const { @@ -1352,8 +1388,6 @@ public: } unsigned getIndexTypeCVRQualifiers() const { return IndexTypeQuals; } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || T->getTypeClass() == VariableArray || @@ -1629,6 +1663,9 @@ protected: : Type(tc, canonType, vecType->isDependentType()), ElementType(vecType), NumElements(nElements), AltiVec(isAltiVec), Pixel(isPixel) {} friend class ASTContext; // ASTContext creates these. + + virtual Linkage getLinkageImpl() const; + public: QualType getElementType() const { return ElementType; } @@ -1655,8 +1692,6 @@ public: ID.AddBoolean(isPixel); } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; } @@ -1733,6 +1768,8 @@ public: /// class of FunctionNoProtoType and FunctionProtoType. /// class FunctionType : public Type { + virtual void ANCHOR(); // Key function for FunctionType. + /// SubClassData - This field is owned by the subclass, put here to pack /// tightly with the ivars in Type. bool SubClassData : 1; @@ -1753,7 +1790,7 @@ class FunctionType : public Type { unsigned RegParm : 3; /// CallConv - The calling convention used by the function. - unsigned CallConv : 2; + unsigned CallConv : 3; // The type returned by the function. QualType ResultType; @@ -1821,7 +1858,7 @@ class FunctionType : public Type { // The value passed to __attribute__((regparm(x))) unsigned RegParm; // The calling convention as specified via - // __attribute__((cdecl|stdcall||fastcall)) + // __attribute__((cdecl|stdcall|fastcall|thiscall)) CallingConv CC; }; @@ -1862,6 +1899,10 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { : FunctionType(FunctionNoProto, Result, false, 0, Canonical, /*Dependent=*/false, Info) {} friend class ASTContext; // ASTContext creates these. + +protected: + virtual Linkage getLinkageImpl() const; + public: // No additional state past what FunctionType provides. @@ -1879,8 +1920,6 @@ public: ID.AddPointer(ResultType.getAsOpaquePtr()); } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto; } @@ -1944,6 +1983,9 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. +protected: + virtual Linkage getLinkageImpl() const; + public: unsigned getNumArgs() const { return NumArgs; } QualType getArgType(unsigned i) const { @@ -1984,8 +2026,6 @@ public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() == FunctionProto; } @@ -2190,6 +2230,8 @@ class TagType : public Type { protected: TagType(TypeClass TC, const TagDecl *D, QualType can); + virtual Linkage getLinkageImpl() const; + public: TagDecl *getDecl() const { return decl.getPointer(); } @@ -2198,8 +2240,6 @@ public: bool isBeingDefined() const { return decl.getInt(); } void setBeingDefined(bool Def) const { decl.setInt(Def? 1 : 0); } - virtual Linkage getLinkage() const; - static bool classof(const Type *T) { return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast; } @@ -2264,68 +2304,6 @@ public: static bool classof(const EnumType *) { return true; } }; -/// ElaboratedType - A non-canonical type used to represents uses of -/// elaborated type specifiers in C++. For example: -/// -/// void foo(union MyUnion); -/// ^^^^^^^^^^^^^ -/// -/// At the moment, for efficiency we do not create elaborated types in -/// C, since outside of typedefs all references to structs would -/// necessarily be elaborated. -class ElaboratedType : public Type, public llvm::FoldingSetNode { -public: - enum TagKind { - TK_struct, - TK_union, - TK_class, - TK_enum - }; - -private: - /// The tag that was used in this elaborated type specifier. - TagKind Tag; - - /// The underlying type. - QualType UnderlyingType; - - explicit ElaboratedType(QualType Ty, TagKind Tag, QualType Canon) - : Type(Elaborated, Canon, Canon->isDependentType()), - Tag(Tag), UnderlyingType(Ty) { } - friend class ASTContext; // ASTContext creates these. - -public: - TagKind getTagKind() const { return Tag; } - QualType getUnderlyingType() const { return UnderlyingType; } - - /// \brief Remove a single level of sugar. - QualType desugar() const { return getUnderlyingType(); } - - /// \brief Returns whether this type directly provides sugar. - bool isSugared() const { return true; } - - static const char *getNameForTagKind(TagKind Kind) { - switch (Kind) { - default: assert(0 && "Unknown TagKind!"); - case TK_struct: return "struct"; - case TK_union: return "union"; - case TK_class: return "class"; - case TK_enum: return "enum"; - } - } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getUnderlyingType(), getTagKind()); - } - static void Profile(llvm::FoldingSetNodeID &ID, QualType T, TagKind Tag) { - ID.AddPointer(T.getAsOpaquePtr()); - ID.AddInteger(Tag); - } - - static bool classof(const ElaboratedType*) { return true; } - static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; } -}; - class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { unsigned Depth : 15; unsigned Index : 16; @@ -2592,46 +2570,116 @@ public: static bool classof(const InjectedClassNameType *T) { return true; } }; +/// \brief The kind of a tag type. +enum TagTypeKind { + /// \brief The "struct" keyword. + TTK_Struct, + /// \brief The "union" keyword. + TTK_Union, + /// \brief The "class" keyword. + TTK_Class, + /// \brief The "enum" keyword. + TTK_Enum +}; + /// \brief The elaboration keyword that precedes a qualified type name or /// introduces an elaborated-type-specifier. enum ElaboratedTypeKeyword { - /// \brief No keyword precedes the qualified type name. - ETK_None, - /// \brief The "typename" keyword precedes the qualified type name, e.g., - /// \c typename T::type. - ETK_Typename, - /// \brief The "class" keyword introduces the elaborated-type-specifier. - ETK_Class, /// \brief The "struct" keyword introduces the elaborated-type-specifier. ETK_Struct, /// \brief The "union" keyword introduces the elaborated-type-specifier. ETK_Union, + /// \brief The "class" keyword introduces the elaborated-type-specifier. + ETK_Class, /// \brief The "enum" keyword introduces the elaborated-type-specifier. - ETK_Enum + ETK_Enum, + /// \brief The "typename" keyword precedes the qualified type name, e.g., + /// \c typename T::type. + ETK_Typename, + /// \brief No keyword precedes the qualified type name. + ETK_None }; - -/// \brief Represents a type that was referred to via a qualified -/// name, e.g., N::M::type. + +/// A helper class for Type nodes having an ElaboratedTypeKeyword. +/// The keyword in stored in the free bits of the base class. +/// Also provides a few static helpers for converting and printing +/// elaborated type keyword and tag type kind enumerations. +class TypeWithKeyword : public Type { + /// Keyword - Encodes an ElaboratedTypeKeyword enumeration constant. + unsigned Keyword : 3; + +protected: + TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, + QualType Canonical, bool dependent) + : Type(tc, Canonical, dependent), Keyword(Keyword) {} + +public: + virtual ~TypeWithKeyword(); // pin vtable to Type.cpp + + ElaboratedTypeKeyword getKeyword() const { + return static_cast<ElaboratedTypeKeyword>(Keyword); + } + + /// getKeywordForTypeSpec - Converts a type specifier (DeclSpec::TST) + /// into an elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); + + /// getTagTypeKindForTypeSpec - Converts a type specifier (DeclSpec::TST) + /// into a tag type kind. It is an error to provide a type specifier + /// which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); + + /// getKeywordForTagDeclKind - Converts a TagTypeKind into an + /// elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); + + /// getTagTypeKindForKeyword - Converts an elaborated type keyword into + // a TagTypeKind. It is an error to provide an elaborated type keyword + /// which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); + + static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); + + static const char *getKeywordName(ElaboratedTypeKeyword Keyword); + + static const char *getTagTypeKindName(TagTypeKind Kind) { + return getKeywordName(getKeywordForTagTypeKind(Kind)); + } + + class CannotCastToThisType {}; + static CannotCastToThisType classof(const Type *); +}; + +/// \brief Represents a type that was referred to using an elaborated type +/// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type, +/// or both. /// /// This type is used to keep track of a type name as written in the -/// source code, including any nested-name-specifiers. The type itself -/// is always "sugar", used to express what was written in the source -/// code but containing no additional semantic information. -class QualifiedNameType : public Type, public llvm::FoldingSetNode { +/// source code, including tag keywords and any nested-name-specifiers. +/// The type itself is always "sugar", used to express what was written +/// in the source code but containing no additional semantic information. +class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode { + /// \brief The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// \brief The type that this qualified name refers to. QualType NamedType; - QualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType, - QualType CanonType) - : Type(QualifiedName, CanonType, NamedType->isDependentType()), - NNS(NNS), NamedType(NamedType) { } + ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + QualType NamedType, QualType CanonType) + : TypeWithKeyword(Keyword, Elaborated, CanonType, + NamedType->isDependentType()), + NNS(NNS), NamedType(NamedType) { + assert(!(Keyword == ETK_None && NNS == 0) && + "ElaboratedType cannot have elaborated type keyword " + "and name qualifier both null."); + } friend class ASTContext; // ASTContext creates these public: + /// \brief Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } @@ -2645,19 +2693,20 @@ public: bool isSugared() const { return true; } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, NNS, NamedType); + Profile(ID, getKeyword(), NNS, NamedType); } - static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, - QualType NamedType) { + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, QualType NamedType) { + ID.AddInteger(Keyword); ID.AddPointer(NNS); NamedType.Profile(ID); } static bool classof(const Type *T) { - return T->getTypeClass() == QualifiedName; + return T->getTypeClass() == Elaborated; } - static bool classof(const QualifiedNameType *T) { return true; } + static bool classof(const ElaboratedType *T) { return true; } }; /// \brief Represents a qualified type name for which the type name is @@ -2669,10 +2718,8 @@ public: /// typename-specifier), "class", "struct", "union", or "enum" (for a /// dependent elaborated-type-specifier), or nothing (in contexts where we /// know that we must be referring to a type, e.g., in a base class specifier). -class DependentNameType : public Type, public llvm::FoldingSetNode { - /// \brief The keyword used to elaborate this type. - ElaboratedTypeKeyword Keyword; - +class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { + /// \brief The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; @@ -2684,16 +2731,16 @@ class DependentNameType : public Type, public llvm::FoldingSetNode { DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType CanonType) - : Type(DependentName, CanonType, true), - Keyword(Keyword), NNS(NNS), Name(Name) { + : TypeWithKeyword(Keyword, DependentName, CanonType, true), + NNS(NNS), Name(Name) { assert(NNS->isDependent() && "DependentNameType requires a dependent nested-name-specifier"); } DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty, QualType CanonType) - : Type(DependentName, CanonType, true), - Keyword(Keyword), NNS(NNS), Name(Ty) { + : TypeWithKeyword(Keyword, DependentName, CanonType, true), + NNS(NNS), Name(Ty) { assert(NNS->isDependent() && "DependentNameType requires a dependent nested-name-specifier"); } @@ -2701,9 +2748,7 @@ class DependentNameType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these public: - /// \brief Retrieve the keyword used to elaborate this type. - ElaboratedTypeKeyword getKeyword() const { return Keyword; } - + /// \brief Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } @@ -2727,7 +2772,7 @@ public: QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Keyword, NNS, Name); + Profile(ID, getKeyword(), NNS, Name); } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, @@ -2743,153 +2788,333 @@ public: static bool classof(const DependentNameType *T) { return true; } }; -/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for -/// object oriented design. They basically correspond to C++ classes. There -/// are two kinds of interface types, normal interfaces like "NSString" and -/// qualified interfaces, which are qualified with a protocol list like -/// "NSString<NSCopyable, NSAmazing>". -class ObjCInterfaceType : public Type, public llvm::FoldingSetNode { - ObjCInterfaceDecl *Decl; +/// ObjCObjectType - Represents a class type in Objective C. +/// Every Objective C type is a combination of a base type and a +/// list of protocols. +/// +/// Given the following declarations: +/// @class C; +/// @protocol P; +/// +/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType +/// with base C and no protocols. +/// +/// 'C<P>' is an ObjCObjectType with base C and protocol list [P]. +/// +/// 'id' is a TypedefType which is sugar for an ObjCPointerType whose +/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType +/// and no protocols. +/// +/// 'id<P>' is an ObjCPointerType whose pointee is an ObjCObjecType +/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually +/// this should get its own sugar class to better represent the source. +class ObjCObjectType : public Type { + // Pad the bit count up so that NumProtocols is 2-byte aligned + unsigned : BitsRemainingInType - 16; + + /// \brief The number of protocols stored after the + /// ObjCObjectPointerType node. + /// + /// These protocols are those written directly on the type. If + /// protocol qualifiers ever become additive, the iterators will + /// get kindof complicated. + /// + /// In the canonical object type, these are sorted alphabetically + /// and uniqued. + unsigned NumProtocols : 16; - /// \brief The number of protocols stored after the ObjCInterfaceType node. - /// The list of protocols is sorted on protocol name. No protocol is enterred - /// more than once. - unsigned NumProtocols; + /// Either a BuiltinType or an InterfaceType or sugar for either. + QualType BaseType; - ObjCInterfaceType(QualType Canonical, ObjCInterfaceDecl *D, - ObjCProtocolDecl **Protos, unsigned NumP); - friend class ASTContext; // ASTContext creates these. + ObjCProtocolDecl * const *getProtocolStorage() const { + return const_cast<ObjCObjectType*>(this)->getProtocolStorage(); + } + + ObjCProtocolDecl **getProtocolStorage(); + +protected: + ObjCObjectType(QualType Canonical, QualType Base, + ObjCProtocolDecl * const *Protocols, unsigned NumProtocols); + + enum Nonce_ObjCInterface { Nonce_ObjCInterface }; + ObjCObjectType(enum Nonce_ObjCInterface) + : Type(ObjCInterface, QualType(), false), + NumProtocols(0), + BaseType(QualType(this_(), 0)) {} + +protected: + Linkage getLinkageImpl() const; // key function + public: - void Destroy(ASTContext& C); + /// getBaseType - Gets the base type of this object type. This is + /// always (possibly sugar for) one of: + /// - the 'id' builtin type (as opposed to the 'id' type visible to the + /// user, which is a typedef for an ObjCPointerType) + /// - the 'Class' builtin type (same caveat) + /// - an ObjCObjectType (currently always an ObjCInterfaceType) + QualType getBaseType() const { return BaseType; } + + bool isObjCId() const { + return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId); + } + bool isObjCClass() const { + return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass); + } + bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); } + bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); } + bool isObjCUnqualifiedIdOrClass() const { + if (!qual_empty()) return false; + if (const BuiltinType *T = getBaseType()->getAs<BuiltinType>()) + return T->getKind() == BuiltinType::ObjCId || + T->getKind() == BuiltinType::ObjCClass; + return false; + } + bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); } + bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); } - ObjCInterfaceDecl *getDecl() const { return Decl; } + /// Gets the interface declaration for this object type, if the base type + /// really is an interface. + ObjCInterfaceDecl *getInterface() const; + + typedef ObjCProtocolDecl * const *qual_iterator; + + qual_iterator qual_begin() const { return getProtocolStorage(); } + qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); } + + bool qual_empty() const { return getNumProtocols() == 0; } /// getNumProtocols - Return the number of qualifying protocols in this /// interface type, or 0 if there are none. unsigned getNumProtocols() const { return NumProtocols; } - /// \brief Retrieve the Ith protocol. + /// \brief Fetch a protocol by index. ObjCProtocolDecl *getProtocol(unsigned I) const { assert(I < getNumProtocols() && "Out-of-range protocol access"); return qual_begin()[I]; } - /// qual_iterator and friends: this provides access to the (potentially empty) - /// list of protocols qualifying this interface. - typedef ObjCProtocolDecl* const * qual_iterator; - qual_iterator qual_begin() const { - return reinterpret_cast<qual_iterator>(this + 1); - } - qual_iterator qual_end() const { - return qual_begin() + NumProtocols; - } - bool qual_empty() const { return NumProtocols == 0; } - bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCObject || + T->getTypeClass() == ObjCInterface; + } + static bool classof(const ObjCObjectType *) { return true; } +}; + +/// ObjCObjectTypeImpl - A class providing a concrete implementation +/// of ObjCObjectType, so as to not increase the footprint of +/// ObjCInterfaceType. Code outside of ASTContext and the core type +/// system should not reference this type. +class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { + friend class ASTContext; + + // If anyone adds fields here, ObjCObjectType::getProtocolStorage() + // will need to be modified. + + ObjCObjectTypeImpl(QualType Canonical, QualType Base, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) + : ObjCObjectType(Canonical, Base, Protocols, NumProtocols) {} + +public: + void Destroy(ASTContext& C); // key function + void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl * const *protocols, - unsigned NumProtocols); + QualType Base, + ObjCProtocolDecl *const *protocols, + unsigned NumProtocols); +}; - virtual Linkage getLinkage() const; +inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() { + return reinterpret_cast<ObjCProtocolDecl**>( + static_cast<ObjCObjectTypeImpl*>(this) + 1); +} + +/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for +/// object oriented design. They basically correspond to C++ classes. There +/// are two kinds of interface types, normal interfaces like "NSString" and +/// qualified interfaces, which are qualified with a protocol list like +/// "NSString<NSCopyable, NSAmazing>". +/// +/// ObjCInterfaceType guarantees the following properties when considered +/// as a subtype of its superclass, ObjCObjectType: +/// - There are no protocol qualifiers. To reinforce this, code which +/// tries to invoke the protocol methods via an ObjCInterfaceType will +/// fail to compile. +/// - It is its own base type. That is, if T is an ObjCInterfaceType*, +/// T->getBaseType() == QualType(T, 0). +class ObjCInterfaceType : public ObjCObjectType { + ObjCInterfaceDecl *Decl; + + ObjCInterfaceType(const ObjCInterfaceDecl *D) + : ObjCObjectType(Nonce_ObjCInterface), + Decl(const_cast<ObjCInterfaceDecl*>(D)) {} + friend class ASTContext; // ASTContext creates these. +public: + void Destroy(ASTContext& C); // key function + + /// getDecl - Get the declaration of this interface. + ObjCInterfaceDecl *getDecl() const { return Decl; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCInterface; } static bool classof(const ObjCInterfaceType *) { return true; } + + // Nonsense to "hide" certain members of ObjCObjectType within this + // class. People asking for protocols on an ObjCInterfaceType are + // not going to get what they want: ObjCInterfaceTypes are + // guaranteed to have no protocols. + enum { + qual_iterator, + qual_begin, + qual_end, + getNumProtocols, + getProtocol + }; }; -/// ObjCObjectPointerType - Used to represent 'id', 'Interface *', 'id <p>', -/// and 'Interface <p> *'. +inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { + if (const ObjCInterfaceType *T = + getBaseType()->getAs<ObjCInterfaceType>()) + return T->getDecl(); + return 0; +} + +/// ObjCObjectPointerType - Used to represent a pointer to an +/// Objective C object. These are constructed from pointer +/// declarators when the pointee type is an ObjCObjectType (or sugar +/// for one). In addition, the 'id' and 'Class' types are typedefs +/// for these, and the protocol-qualified types 'id<P>' and 'Class<P>' +/// are translated into these. /// -/// Duplicate protocols are removed and protocol list is canonicalized to be in -/// alphabetical order. +/// Pointers to pointers to Objective C objects are still PointerTypes; +/// only the first level of pointer gets it own type implementation. class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { - QualType PointeeType; // A builtin or interface type. - - /// \brief The number of protocols stored after the ObjCObjectPointerType - /// node. - /// - /// The list of protocols is sorted on protocol name. No protocol is enterred - /// more than once. - unsigned NumProtocols; + QualType PointeeType; - ObjCObjectPointerType(QualType Canonical, QualType T, - ObjCProtocolDecl **Protos, unsigned NumP); + ObjCObjectPointerType(QualType Canonical, QualType Pointee) + : Type(ObjCObjectPointer, Canonical, false), + PointeeType(Pointee) {} friend class ASTContext; // ASTContext creates these. +protected: + virtual Linkage getLinkageImpl() const; + public: void Destroy(ASTContext& C); - // Get the pointee type. Pointee will either be: - // - a built-in type (for 'id' and 'Class'). - // - an interface type (for user-defined types). - // - a TypedefType whose canonical type is an interface (as in 'T' below). - // For example: typedef NSObject T; T *var; + /// getPointeeType - Gets the type pointed to by this ObjC pointer. + /// The result will always be an ObjCObjectType or sugar thereof. QualType getPointeeType() const { return PointeeType; } + /// getObjCObjectType - Gets the type pointed to by this ObjC + /// pointer. This method always returns non-null. + /// + /// This method is equivalent to getPointeeType() except that + /// it discards any typedefs (or other sugar) between this + /// type and the "outermost" object type. So for: + /// @class A; @protocol P; @protocol Q; + /// typedef A<P> AP; + /// typedef A A1; + /// typedef A1<P> A1P; + /// typedef A1P<Q> A1PQ; + /// For 'A*', getObjectType() will return 'A'. + /// For 'A<P>*', getObjectType() will return 'A<P>'. + /// For 'AP*', getObjectType() will return 'A<P>'. + /// For 'A1*', getObjectType() will return 'A'. + /// For 'A1<P>*', getObjectType() will return 'A1<P>'. + /// For 'A1P*', getObjectType() will return 'A1<P>'. + /// For 'A1PQ*', getObjectType() will return 'A1<Q>', because + /// adding protocols to a protocol-qualified base discards the + /// old qualifiers (for now). But if it didn't, getObjectType() + /// would return 'A1P<Q>' (and we'd have to make iterating over + /// qualifiers more complicated). + const ObjCObjectType *getObjectType() const { + return PointeeType->getAs<ObjCObjectType>(); + } + + /// getInterfaceType - If this pointer points to an Objective C + /// @interface type, gets the type for that interface. Any protocol + /// qualifiers on the interface are ignored. + /// + /// \return null if the base type for this pointer is 'id' or 'Class' const ObjCInterfaceType *getInterfaceType() const { - return PointeeType->getAs<ObjCInterfaceType>(); + return getObjectType()->getBaseType()->getAs<ObjCInterfaceType>(); } - /// getInterfaceDecl - returns an interface decl for user-defined types. + + /// getInterfaceDecl - If this pointer points to an Objective @interface + /// type, gets the declaration for that interface. + /// + /// \return null if the base type for this pointer is 'id' or 'Class' ObjCInterfaceDecl *getInterfaceDecl() const { - return getInterfaceType() ? getInterfaceType()->getDecl() : 0; + return getObjectType()->getInterface(); } - /// isObjCIdType - true for "id". + + /// isObjCIdType - True if this is equivalent to the 'id' type, i.e. if + /// its object type is the primitive 'id' type with no protocols. bool isObjCIdType() const { - return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && - !NumProtocols; + return getObjectType()->isObjCUnqualifiedId(); } - /// isObjCClassType - true for "Class". + + /// isObjCClassType - True if this is equivalent to the 'Class' type, + /// i.e. if its object tive is the primitive 'Class' type with no protocols. bool isObjCClassType() const { - return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) && - !NumProtocols; + return getObjectType()->isObjCUnqualifiedClass(); } - /// isObjCQualifiedIdType - true for "id <p>". + /// isObjCQualifiedIdType - True if this is equivalent to 'id<P>' for some + /// non-empty set of protocols. bool isObjCQualifiedIdType() const { - return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && - NumProtocols; + return getObjectType()->isObjCQualifiedId(); } - /// isObjCQualifiedClassType - true for "Class <p>". + + /// isObjCQualifiedClassType - True if this is equivalent to 'Class<P>' for + /// some non-empty set of protocols. bool isObjCQualifiedClassType() const { - return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) && - NumProtocols; + return getObjectType()->isObjCQualifiedClass(); } - /// qual_iterator and friends: this provides access to the (potentially empty) - /// list of protocols qualifying this interface. - typedef ObjCProtocolDecl* const * qual_iterator; + + /// An iterator over the qualifiers on the object type. Provided + /// for convenience. This will always iterate over the full set of + /// protocols on a type, not just those provided directly. + typedef ObjCObjectType::qual_iterator qual_iterator; qual_iterator qual_begin() const { - return reinterpret_cast<qual_iterator> (this + 1); + return getObjectType()->qual_begin(); } - qual_iterator qual_end() const { - return qual_begin() + NumProtocols; + qual_iterator qual_end() const { + return getObjectType()->qual_end(); } - bool qual_empty() const { return NumProtocols == 0; } + bool qual_empty() const { return getObjectType()->qual_empty(); } - /// getNumProtocols - Return the number of qualifying protocols in this - /// interface type, or 0 if there are none. - unsigned getNumProtocols() const { return NumProtocols; } + /// getNumProtocols - Return the number of qualifying protocols on + /// the object type. + unsigned getNumProtocols() const { + return getObjectType()->getNumProtocols(); + } - /// \brief Retrieve the Ith protocol. + /// \brief Retrieve a qualifying protocol by index on the object + /// type. ObjCProtocolDecl *getProtocol(unsigned I) const { - assert(I < getNumProtocols() && "Out-of-range protocol access"); - return qual_begin()[I]; + return getObjectType()->getProtocol(I); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } - virtual Linkage getLinkage() const; - - void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, QualType T, - ObjCProtocolDecl *const *protocols, - unsigned NumProtocols); + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + ID.AddPointer(T.getAsOpaquePtr()); + } static bool classof(const Type *T) { return T->getTypeClass() == ObjCObjectPointer; } @@ -3128,12 +3353,6 @@ inline QualType QualType::getNonReferenceType() const { return *this; } -inline const ObjCInterfaceType *Type::getAsPointerToObjCInterfaceType() const { - if (const PointerType *PT = getAs<PointerType>()) - return PT->getPointeeType()->getAs<ObjCInterfaceType>(); - return 0; -} - inline bool Type::isFunctionType() const { return isa<FunctionType>(CanonicalType); } @@ -3200,8 +3419,8 @@ inline bool Type::isExtVectorType() const { inline bool Type::isObjCObjectPointerType() const { return isa<ObjCObjectPointerType>(CanonicalType); } -inline bool Type::isObjCInterfaceType() const { - return isa<ObjCInterfaceType>(CanonicalType); +inline bool Type::isObjCObjectType() const { + return isa<ObjCObjectType>(CanonicalType); } inline bool Type::isObjCQualifiedIdType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) @@ -3250,13 +3469,11 @@ inline bool Type::isOverloadableType() const { inline bool Type::hasPointerRepresentation() const { return (isPointerType() || isReferenceType() || isBlockPointerType() || - isObjCInterfaceType() || isObjCObjectPointerType() || - isObjCQualifiedInterfaceType() || isNullPtrType()); + isObjCObjectPointerType() || isNullPtrType()); } inline bool Type::hasObjCPointerRepresentation() const { - return (isObjCInterfaceType() || isObjCObjectPointerType() || - isObjCQualifiedInterfaceType()); + return isObjCObjectPointerType(); } /// Insertion operator for diagnostics. This allows sending QualType's into a diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index a51da7474d37..f988f0e33b39 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_TYPELOC_H #include "clang/AST/Type.h" +#include "clang/AST/Decl.h" #include "clang/AST/TemplateBase.h" #include "clang/Basic/Specifiers.h" @@ -84,21 +85,20 @@ public: return Data; } + /// \brief Get the begin source location. + SourceLocation getBeginLoc() const; + + /// \brief Get the end source location. + SourceLocation getEndLoc() const; + /// \brief Get the full source range. - SourceRange getFullSourceRange() const { - SourceLocation End = getSourceRange().getEnd(); - TypeLoc Cur = *this; - while (true) { - TypeLoc Next = Cur.getNextTypeLoc(); - if (Next.isNull()) break; - Cur = Next; - } - return SourceRange(Cur.getSourceRange().getBegin(), End); + SourceRange getSourceRange() const { + return SourceRange(getBeginLoc(), getEndLoc()); } /// \brief Get the local source range. - SourceRange getSourceRange() const { - return getSourceRangeImpl(*this); + SourceRange getLocalSourceRange() const { + return getLocalSourceRangeImpl(*this); } /// \brief Returns the size of the type source info data block. @@ -137,9 +137,14 @@ public: private: static void initializeImpl(TypeLoc TL, SourceLocation Loc); static TypeLoc getNextTypeLocImpl(TypeLoc TL); - static SourceRange getSourceRangeImpl(TypeLoc TL); + static SourceRange getLocalSourceRangeImpl(TypeLoc TL); }; +/// \brief Return the TypeLoc for a type source info. +inline TypeLoc TypeSourceInfo::getTypeLoc() const { + return TypeLoc(Ty, (void*)(this + 1)); +} + /// \brief Wrapper of type source information for a type with /// no direct quqlaifiers. class UnqualTypeLoc : public TypeLoc { @@ -168,7 +173,7 @@ public: /// type qualifiers. class QualifiedTypeLoc : public TypeLoc { public: - SourceRange getSourceRange() const { + SourceRange getLocalSourceRange() const { return SourceRange(); } @@ -263,6 +268,16 @@ public: return TypeClass::classof(Ty); } + static bool classof(const TypeLoc *TL) { + return Derived::classofType(TL->getTypePtr()); + } + static bool classof(const UnqualTypeLoc *TL) { + return Derived::classofType(TL->getTypePtr()); + } + static bool classof(const Derived *TL) { + return true; + } + TypeLoc getNextTypeLoc() const { return getNextTypeLoc(asDerived()->getInnerType()); } @@ -361,7 +376,7 @@ public: void setNameLoc(SourceLocation Loc) { this->getLocalData()->NameLoc = Loc; } - SourceRange getSourceRange() const { + SourceRange getLocalSourceRange() const { return SourceRange(getNameLoc(), getNameLoc()); } void initializeLocal(SourceLocation Loc) { @@ -413,7 +428,7 @@ public: return needsExtraLocalData() ? sizeof(WrittenBuiltinSpecs) : 0; } - SourceRange getSourceRange() const { + SourceRange getLocalSourceRange() const { return SourceRange(getBuiltinLoc(), getBuiltinLoc()); } @@ -553,6 +568,7 @@ class SubstTemplateTypeParmTypeLoc : struct ObjCProtocolListLocInfo { SourceLocation LAngleLoc; SourceLocation RAngleLoc; + bool HasBaseTypeAsWritten; }; // A helper class for defining ObjC TypeLocs that can qualified with @@ -560,24 +576,15 @@ struct ObjCProtocolListLocInfo { // // TypeClass basically has to be either ObjCInterfaceType or // ObjCObjectPointerType. -template <class Derived, class TypeClass, class LocalData> -class ObjCProtocolListTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, - Derived, - TypeClass, - LocalData> { +class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ObjCObjectTypeLoc, + ObjCObjectType, + ObjCProtocolListLocInfo> { // SourceLocations are stored after Info, one for each Protocol. SourceLocation *getProtocolLocArray() const { return (SourceLocation*) this->getExtraLocalData(); } -protected: - void initializeLocalBase(SourceLocation Loc) { - setLAngleLoc(Loc); - setRAngleLoc(Loc); - for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) - setProtocolLoc(i, Loc); - } - public: SourceLocation getLAngleLoc() const { return this->getLocalData()->LAngleLoc; @@ -611,29 +618,49 @@ public: return *(this->getTypePtr()->qual_begin() + i); } - SourceRange getSourceRange() const { + bool hasBaseTypeAsWritten() const { + return getLocalData()->HasBaseTypeAsWritten; + } + + void setHasBaseTypeAsWritten(bool HasBaseType) { + getLocalData()->HasBaseTypeAsWritten = HasBaseType; + } + + TypeLoc getBaseLoc() const { + return getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { return SourceRange(getLAngleLoc(), getRAngleLoc()); } void initializeLocal(SourceLocation Loc) { - initializeLocalBase(Loc); + setHasBaseTypeAsWritten(true); + setLAngleLoc(Loc); + setRAngleLoc(Loc); + for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) + setProtocolLoc(i, Loc); } unsigned getExtraLocalDataSize() const { return this->getNumProtocols() * sizeof(SourceLocation); } + + QualType getInnerType() const { + return getTypePtr()->getBaseType(); + } }; -struct ObjCInterfaceLocInfo : ObjCProtocolListLocInfo { +struct ObjCInterfaceLocInfo { SourceLocation NameLoc; }; /// \brief Wrapper for source info for ObjC interfaces. -class ObjCInterfaceTypeLoc : - public ObjCProtocolListTypeLoc<ObjCInterfaceTypeLoc, - ObjCInterfaceType, - ObjCInterfaceLocInfo> { +class ObjCInterfaceTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ObjCInterfaceTypeLoc, + ObjCInterfaceType, + ObjCInterfaceLocInfo> { public: ObjCInterfaceDecl *getIFaceDecl() const { return getTypePtr()->getDecl(); @@ -647,85 +674,16 @@ public: getLocalData()->NameLoc = Loc; } - SourceRange getSourceRange() const { - if (getNumProtocols()) - return SourceRange(getNameLoc(), getRAngleLoc()); - else - return SourceRange(getNameLoc(), getNameLoc()); + SourceRange getLocalSourceRange() const { + return SourceRange(getNameLoc()); } void initializeLocal(SourceLocation Loc) { - initializeLocalBase(Loc); setNameLoc(Loc); } }; -struct ObjCObjectPointerLocInfo : ObjCProtocolListLocInfo { - SourceLocation StarLoc; - bool HasProtocols; - bool HasBaseType; -}; - -/// Wraps an ObjCPointerType with source location information. Note -/// that not all ObjCPointerTypes actually have a star location; nor -/// are protocol locations necessarily written in the source just -/// because they're present on the type. -class ObjCObjectPointerTypeLoc : - public ObjCProtocolListTypeLoc<ObjCObjectPointerTypeLoc, - ObjCObjectPointerType, - ObjCObjectPointerLocInfo> { -public: - bool hasProtocolsAsWritten() const { - return getLocalData()->HasProtocols; - } - - void setHasProtocolsAsWritten(bool HasProtocols) { - getLocalData()->HasProtocols = HasProtocols; - } - - bool hasBaseTypeAsWritten() const { - return getLocalData()->HasBaseType; - } - - void setHasBaseTypeAsWritten(bool HasBaseType) { - getLocalData()->HasBaseType = HasBaseType; - } - - SourceLocation getStarLoc() const { - return getLocalData()->StarLoc; - } - - void setStarLoc(SourceLocation Loc) { - getLocalData()->StarLoc = Loc; - } - - SourceRange getSourceRange() const { - // Being written with protocols is incompatible with being written - // with a star. - if (hasProtocolsAsWritten()) - return SourceRange(getLAngleLoc(), getRAngleLoc()); - else - return SourceRange(getStarLoc(), getStarLoc()); - } - - void initializeLocal(SourceLocation Loc) { - initializeLocalBase(Loc); - setHasProtocolsAsWritten(false); - setHasBaseTypeAsWritten(false); - setStarLoc(Loc); - } - - TypeLoc getBaseTypeLoc() const { - return getInnerTypeLoc(); - } - - QualType getInnerType() const { - return getTypePtr()->getPointeeType(); - } -}; - - struct PointerLikeLocInfo { SourceLocation StarLoc; }; @@ -746,7 +704,7 @@ public: return this->getInnerTypeLoc(); } - SourceRange getSourceRange() const { + SourceRange getLocalSourceRange() const { return SourceRange(getSigilLoc(), getSigilLoc()); } @@ -798,6 +756,20 @@ public: } }; +/// Wraps an ObjCPointerType with source location information. +class ObjCObjectPointerTypeLoc : + public PointerLikeTypeLoc<ObjCObjectPointerTypeLoc, + ObjCObjectPointerType> { +public: + SourceLocation getStarLoc() const { + return getSigilLoc(); + } + + void setStarLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + class ReferenceTypeLoc : public PointerLikeTypeLoc<ReferenceTypeLoc, ReferenceType> { @@ -871,13 +843,11 @@ public: ParmVarDecl *getArg(unsigned i) const { return getParmArray()[i]; } void setArg(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; } - TypeLoc getArgLoc(unsigned i) const; - TypeLoc getResultLoc() const { return getInnerTypeLoc(); } - SourceRange getSourceRange() const { + SourceRange getLocalSourceRange() const { return SourceRange(getLParenLoc(), getRParenLoc()); } @@ -950,7 +920,7 @@ public: return getInnerTypeLoc(); } - SourceRange getSourceRange() const { + SourceRange getLocalSourceRange() const { return SourceRange(getLBracketLoc(), getRBracketLoc()); } @@ -1055,7 +1025,7 @@ public: memcpy(Data, Loc.Data, size); } - SourceRange getSourceRange() const { + SourceRange getLocalSourceRange() const { return SourceRange(getTemplateNameLoc(), getRAngleLoc()); } @@ -1183,7 +1153,7 @@ public: setRParenLoc(range.getEnd()); } - SourceRange getSourceRange() const { + SourceRange getLocalSourceRange() const { return SourceRange(getTypeofLoc(), getRParenLoc()); } @@ -1204,7 +1174,7 @@ public: // Reimplemented to account for GNU/C++ extension // typeof unary-expression // where there are no parentheses. - SourceRange getSourceRange() const; + SourceRange getLocalSourceRange() const; }; class TypeOfTypeLoc @@ -1227,24 +1197,110 @@ class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DecltypeType> { }; -// FIXME: location of the tag keyword. -class ElaboratedTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - ElaboratedTypeLoc, - ElaboratedType> { +struct ElaboratedLocInfo { + SourceLocation KeywordLoc; + SourceRange QualifierRange; }; -// FIXME: locations for the nested name specifier; at the very least, -// a SourceRange. -class QualifiedNameTypeLoc : - public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - QualifiedNameTypeLoc, - QualifiedNameType> { +class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ElaboratedTypeLoc, + ElaboratedType, + ElaboratedLocInfo> { +public: + SourceLocation getKeywordLoc() const { + return this->getLocalData()->KeywordLoc; + } + void setKeywordLoc(SourceLocation Loc) { + this->getLocalData()->KeywordLoc = Loc; + } + + SourceRange getQualifierRange() const { + return this->getLocalData()->QualifierRange; + } + void setQualifierRange(SourceRange Range) { + this->getLocalData()->QualifierRange = Range; + } + + SourceRange getLocalSourceRange() const { + if (getKeywordLoc().isValid()) + if (getQualifierRange().getEnd().isValid()) + return SourceRange(getKeywordLoc(), getQualifierRange().getEnd()); + else + return SourceRange(getKeywordLoc()); + else + return getQualifierRange(); + } + + void initializeLocal(SourceLocation Loc) { + setKeywordLoc(Loc); + setQualifierRange(SourceRange(Loc)); + } + + TypeLoc getNamedTypeLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return getTypePtr()->getNamedType(); + } + + void copy(ElaboratedTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + memcpy(Data, Loc.Data, size); + } }; -// FIXME: locations for the typename keyword and nested name specifier. -class DependentNameTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - DependentNameTypeLoc, - DependentNameType> { +struct DependentNameLocInfo { + SourceLocation KeywordLoc; + SourceRange QualifierRange; + SourceLocation NameLoc; +}; + +class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + DependentNameTypeLoc, + DependentNameType, + DependentNameLocInfo> { +public: + SourceLocation getKeywordLoc() const { + return this->getLocalData()->KeywordLoc; + } + void setKeywordLoc(SourceLocation Loc) { + this->getLocalData()->KeywordLoc = Loc; + } + + SourceRange getQualifierRange() const { + return this->getLocalData()->QualifierRange; + } + void setQualifierRange(SourceRange Range) { + this->getLocalData()->QualifierRange = Range; + } + + SourceLocation getNameLoc() const { + return this->getLocalData()->NameLoc; + } + void setNameLoc(SourceLocation Loc) { + this->getLocalData()->NameLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + if (getKeywordLoc().isValid()) + return SourceRange(getKeywordLoc(), getNameLoc()); + else + return SourceRange(getQualifierRange().getBegin(), getNameLoc()); + } + + void copy(DependentNameTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + memcpy(Data, Loc.Data, size); + } + + void initializeLocal(SourceLocation Loc) { + setKeywordLoc(Loc); + setQualifierRange(SourceRange(Loc)); + setNameLoc(Loc); + } }; } diff --git a/include/clang/AST/TypeLocBuilder.h b/include/clang/AST/TypeLocBuilder.h index c3b1c68b1fb6..e729488e4313 100644 --- a/include/clang/AST/TypeLocBuilder.h +++ b/include/clang/AST/TypeLocBuilder.h @@ -59,6 +59,20 @@ class TypeLocBuilder { grow(Requested); } + /// Pushes a copy of the given TypeLoc onto this builder. The builder + /// must be empty for this to work. + void pushFullCopy(TypeLoc L) { +#ifndef NDEBUG + assert(LastTy.isNull() && "pushing copy on non-empty TypeLocBuilder"); + LastTy = L.getNextTypeLoc().getType(); +#endif + assert(Index == Capacity && "pushing copy on non-empty TypeLocBuilder"); + + unsigned Size = L.getFullDataSize(); + TypeLoc Copy = pushImpl(L.getType(), Size); + memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size); + } + /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs /// previously retrieved from this builder. TypeSpecTypeLoc pushTypeSpec(QualType T) { diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index c665073025f7..02508af67dd8 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -90,10 +90,10 @@ NON_CANONICAL_TYPE(Elaborated, Type) DEPENDENT_TYPE(TemplateTypeParm, Type) NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type) NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type) -NON_CANONICAL_TYPE(QualifiedName, Type) DEPENDENT_TYPE(InjectedClassName, Type) DEPENDENT_TYPE(DependentName, Type) -TYPE(ObjCInterface, Type) +TYPE(ObjCObject, Type) +TYPE(ObjCInterface, ObjCObjectType) TYPE(ObjCObjectPointer, Type) #ifdef LAST_TYPE diff --git a/include/clang/AST/TypeVisitor.h b/include/clang/AST/TypeVisitor.h index 19f7f42a897a..5c9c5285a248 100644 --- a/include/clang/AST/TypeVisitor.h +++ b/include/clang/AST/TypeVisitor.h @@ -1,4 +1,4 @@ -//===--- TypeVisitor.h - Visitor for Stmt subclasses ------------*- C++ -*-===// +//===--- TypeVisitor.h - Visitor for Type subclasses ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -25,7 +25,7 @@ template<typename ImplClass, typename RetTy=void> class TypeVisitor { public: RetTy Visit(Type *T) { - // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. + // Top switch stmt: dispatch to VisitFooType for each FooType. switch (T->getTypeClass()) { default: assert(0 && "Unknown type class!"); #define ABSTRACT_TYPE(CLASS, PARENT) diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h index cbe00827d00a..a548b0b704d1 100644 --- a/include/clang/AST/UnresolvedSet.h +++ b/include/clang/AST/UnresolvedSet.h @@ -31,9 +31,13 @@ private: IteratorTy ir; friend class UnresolvedSetImpl; + friend class OverloadExpr; explicit UnresolvedSetIterator(DeclsTy::iterator ir) : ir(ir) {} explicit UnresolvedSetIterator(DeclsTy::const_iterator ir) : ir(const_cast<DeclsTy::iterator>(ir)) {} + + IteratorTy getIterator() const { return ir; } + public: UnresolvedSetIterator() {} @@ -81,9 +85,7 @@ public: bool operator>(const UnresolvedSetIterator &o) const { return ir > o.ir; } }; -/// UnresolvedSet - A set of unresolved declarations. This is needed -/// in a lot of places, but isn't really worth breaking into its own -/// header right now. +/// UnresolvedSet - A set of unresolved declarations. class UnresolvedSetImpl { typedef UnresolvedSetIterator::DeclsTy DeclsTy; diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index fb8d4d5ff53a..075838d45e5c 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -59,7 +59,7 @@ private: protected: ProgramPoint(const void* P, Kind k, const LocationContext *l, const void *tag = 0) - : Data(P, NULL), K(k), L(l), Tag(tag) {} + : Data(P, static_cast<const void*>(NULL)), K(k), L(l), Tag(tag) {} ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l, const void *tag = 0) diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 6b2912e2e8c2..62f06edb7785 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -423,6 +423,14 @@ public: /// the diagnostic, this returns null. static const char *getWarningOptionForDiag(unsigned DiagID); + /// getWarningOptionForDiag - Return the category number that a specified + /// DiagID belongs to, or 0 if no category. + static unsigned getCategoryNumberForDiag(unsigned DiagID); + + /// getCategoryNameFromID - Given a category ID, return the name of the + /// category. + static const char *getCategoryNameFromID(unsigned CategoryID); + /// \brief Enumeration describing how the the emission of a diagnostic should /// be treated when it occurs during C++ template argument deduction. enum SFINAEResponse { diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td index f6b5d9c5b308..fabf9ebb4498 100644 --- a/include/clang/Basic/Diagnostic.td +++ b/include/clang/Basic/Diagnostic.td @@ -42,7 +42,10 @@ class InGroup<DiagGroup G> { DiagGroup Group = G; } //class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; } -// This defines the diagnostic groups that have references to them. +// This defines all of the named diagnostic categories. +include "DiagnosticCategories.td" + +// This defines all of the named diagnostic groups. include "DiagnosticGroups.td" diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index cc89c7caec3c..d755d99e6be5 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -14,17 +14,20 @@ let Component = "AST" in { def note_expr_divide_by_zero : Note<"division by zero">; // inline asm related. -def err_asm_invalid_escape : Error< - "invalid %% escape in inline assembly string">; -def err_asm_unknown_symbolic_operand_name : Error< - "unknown symbolic operand name in inline assembly string">; +let CategoryName = "Inline Assembly Issue" in { + def err_asm_invalid_escape : Error< + "invalid %% escape in inline assembly string">; + def err_asm_unknown_symbolic_operand_name : Error< + "unknown symbolic operand name in inline assembly string">; + + def err_asm_unterminated_symbolic_operand_name : Error< + "unterminated symbolic operand name in inline assembly string">; + def err_asm_empty_symbolic_operand_name : Error< + "empty symbolic operand name in inline assembly string">; + def err_asm_invalid_operand_number : Error< + "invalid operand number in inline asm string">; +} -def err_asm_unterminated_symbolic_operand_name : Error< - "unterminated symbolic operand name in inline assembly string">; -def err_asm_empty_symbolic_operand_name : Error< - "empty symbolic operand name in inline assembly string">; -def err_asm_invalid_operand_number : Error< - "invalid operand number in inline asm string">; // Importing ASTs def err_odr_variable_type_inconsistent : Error< diff --git a/include/clang/Basic/DiagnosticCategories.td b/include/clang/Basic/DiagnosticCategories.td new file mode 100644 index 000000000000..a02fbdf93fc3 --- /dev/null +++ b/include/clang/Basic/DiagnosticCategories.td @@ -0,0 +1,10 @@ +//==--- DiagnosticCategories.td - Diagnostic Category Definitions ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +class CatInlineAsm : DiagCategory<"Inline Assembly Issue">; diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 3b7272e5acc5..f4a31cc5766c 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -49,6 +49,8 @@ def err_drv_no_ast_support : Error< "'%0': unable to use AST files with this tool">; def err_drv_clang_unsupported : Error< "the clang compiler does not support '%0'">; +def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error< + "the clang compiler does not support '%0' for C++ on Darwin/i386">; def err_drv_command_failed : Error< "%0 command failed with exit code %1 (use -v to see invocation)">; def err_drv_command_signalled : Error< diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index b73103067017..c7cad7395c0b 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -16,7 +16,8 @@ def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal; def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal; def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal; -def err_fe_inline_asm : Error<"%0">; // Error generated by the backend. +// Error generated by the backend. +def err_fe_inline_asm : Error<"%0">, CatInlineAsm; def note_fe_inline_asm_here : Note<"generated from here">; def err_fe_invalid_code_complete_file : Error< "cannot locate code-completion file %0">, DefaultFatal; diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 1012e91baa77..b79bf8e2edbe 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -40,6 +40,9 @@ def ExtraTokens : DiagGroup<"extra-tokens">; def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; +def CXXHexFloats : DiagGroup<"c++-hex-floats">; + +def : DiagGroup<"c++0x-compat", [CXXHexFloats]>; def FourByteMultiChar : DiagGroup<"four-char-constants">; def : DiagGroup<"idiomatic-parentheses">; def : DiagGroup<"import">; @@ -120,6 +123,7 @@ def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">; def : DiagGroup<"variadic-macros">; def VariadicMacros : DiagGroup<"variadic-macros">; def VectorConversions : DiagGroup<"vector-conversions">; // clang specific +def VLA : DiagGroup<"vla">; def VolatileRegisterVar : DiagGroup<"volatile-register-var">; def : DiagGroup<"write-strings">; def CharSubscript : DiagGroup<"char-subscripts">; @@ -134,16 +138,17 @@ def Parentheses : DiagGroup<"parentheses", [DiagGroup<"idiomatic-parentheses">]> // legacy reasons. def Conversion : DiagGroup<"conversion", [DiagGroup<"shorten-64-to-32">]>, - DiagCategory<"Value Conversion">; + DiagCategory<"Value Conversion Issue">; def Unused : DiagGroup<"unused", [UnusedArgument, UnusedFunction, UnusedLabel, // UnusedParameter, (matches GCC's behavior) - UnusedValue, UnusedVariable]>; + UnusedValue, UnusedVariable]>, + DiagCategory<"Unused Entity Issue">; // Format settings. def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull]>, - DiagCategory<"Format String">; + DiagCategory<"Format String Issue">; def FormatSecurity : DiagGroup<"format-security", [Format]>; def FormatNonLiteral : DiagGroup<"format-nonliteral", [FormatSecurity]>; def FormatY2K : DiagGroup<"format-y2k", [Format]>; @@ -190,4 +195,4 @@ def NonGCC : DiagGroup<"non-gcc", [SignCompare, Conversion, LiteralRange]>; // A warning group for warnings about GCC extensions. -def GNU : DiagGroup<"gnu", [GNUDesignator]>; +def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>; diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 3f765bdfb3b7..848e85c8ba41 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -11,7 +11,7 @@ // Lexer Diagnostics //===----------------------------------------------------------------------===// -let Component = "Lex" in { +let Component = "Lex", CategoryName = "Lexical or Preprocessor Issue" in { def null_in_string : Warning<"null character(s) preserved in string literal">; def null_in_char : Warning<"null character(s) preserved in character literal">; @@ -84,9 +84,9 @@ def err_exponent_has_no_digits : Error<"exponent has no digits">; def ext_imaginary_constant : Extension<"imaginary constants are an extension">; def err_hexconstant_requires_exponent : Error< "hexadecimal floating constants require an exponent">; -def ext_hexconstant_cplusplus : ExtWarn< +def ext_hexconstant_cplusplus : Extension< "hexadecimal floating constants are a C99 feature that is incompatible with " - "C++0x">; + "C++0x">, InGroup<CXXHexFloats>; def ext_hexconstant_invalid : Extension< "hexadecimal floating constants are a C99 feature">; def ext_binary_literal : Extension< diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 27958515462a..934bd0db1e01 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -13,9 +13,12 @@ let Component = "Parse" in { -def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">; +def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">, + CatInlineAsm; def warn_file_asm_volatile : Warning< - "meaningless 'volatile' on asm outside function">; + "meaningless 'volatile' on asm outside function">, CatInlineAsm; + +let CategoryName = "Parse Issue" in { def ext_empty_source_file : Extension<"ISO C forbids an empty source file">; def ext_top_level_semi : Extension< @@ -119,6 +122,8 @@ def err_expected_semi_after_namespace_name : Error< "expected ';' after namespace name">; def err_unexpected_namespace_attributes_alias : Error< "attributes can not be specified on namespace alias">; +def err_namespace_nonnamespace_scope : Error< + "namespaces can only be defined in global or namespace scope">; def err_expected_semi_after_attribute_list : Error< "expected ';' after attribute list">; def err_expected_semi_after_static_assert : Error< @@ -129,7 +134,7 @@ def err_label_end_of_compound_statement : Error< "label at end of compound statement: expected statement">; def err_expected_string_literal : Error<"expected string literal">; def err_expected_asm_operand : Error< - "expected string literal or '[' for asm operand">; + "expected string literal or '[' for asm operand">, CatInlineAsm; def err_expected_selector_for_method : Error< "expected selector for Objective-C method">; def err_expected_property_name : Error<"expected property name">; @@ -311,6 +316,9 @@ def err_explicit_instantiation_with_definition : Error< "'template' keyword">; def err_enum_template : Error<"enumeration cannot be a template">; +def err_missing_dependent_template_keyword : Error< + "use 'template' keyword to treat '%0' as a dependent template name">; + // Constructor template diagnostics. def err_out_of_line_constructor_template_id : Error< "out-of-line constructor for %0 cannot have template arguments">; @@ -355,6 +363,13 @@ def warn_pragma_expected_identifier : Warning< "expected identifier in '#pragma %0' - ignored">; def warn_pragma_extra_tokens_at_eol : Warning< "extra tokens at end of '#pragma %0' - ignored">; +// - #pragma options +def warn_pragma_options_expected_align : Warning< + "expected 'align' following '#pragma options' - ignored">; +def warn_pragma_options_expected_equal : Warning< + "expected '=' following '#pragma options align' - ignored">; +def warn_pragma_options_invalid_option : Warning< + "invalid alignment option in '#pragma options align' - ignored">; // - #pragma pack def warn_pragma_pack_invalid_action : Warning< "unknown action for '#pragma pack' - ignored">; @@ -368,4 +383,5 @@ def warn_pragma_unused_expected_var : Warning< def warn_pragma_unused_expected_punc : Warning< "expected ')' or ',' in '#pragma unused'">; +} // end of Parse Issue category. } // end of Parser diagnostics diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 6b40820da814..0ba31aee2ff5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// let Component = "Sema" in { +let CategoryName = "Semantic Issue" in { // Constant expressions def err_expr_not_ice : Error< @@ -36,6 +37,28 @@ def warn_float_underflow : Warning< "magnitude of floating-point constant too small for type %0; minimum is %1">, InGroup<LiteralRange>; +// C99 variable-length arrays +def ext_vla : Extension< + "variable length arrays are a C99 feature, accepted as an extension">, + InGroup<VLA>; +def err_vla_non_pod : Error<"variable length array of non-POD element type %0">; +def err_vla_in_sfinae : Error< + "variable length array cannot be formed during template argument deduction">; +def err_array_star_in_function_definition : Error< + "variable length array must be bound in function definition">; +def err_vla_decl_in_file_scope : Error< + "variable length array declaration not allowed at file scope">; +def err_vla_decl_has_static_storage : Error< + "variable length array declaration can not have 'static' storage duration">; +def err_vla_decl_has_extern_linkage : Error< + "variable length array declaration can not have 'extern' linkage">; + +// C99 variably modified types +def err_variably_modified_template_arg : Error< + "variably modified type %0 cannot be used as a template argument">; +def err_variably_modified_nontype_template_param : Error< + "non-type template parameter of variably modified type %0">; + // C99 Designated Initializers def err_array_designator_negative : Error< "array designator value '%0' is negative">; @@ -71,11 +94,6 @@ def ext_flexible_array_init : Extension< "flexible array initialization is a GNU extension">, InGroup<GNU>; // Declarations. -def ext_vla : Extension< - "variable length arrays are a C99 feature, accepted as an extension">; -def err_vla_cxx : Error< - "variable length arrays are not permitted in C++">; - def ext_anon_param_requires_type_specifier : Extension< "type specifier required for unnamed parameter, defaults to int">; def err_bad_variable_name : Error< @@ -89,8 +107,6 @@ def warn_unused_exception_param : Warning<"unused exception parameter %0">, InGroup<UnusedExceptionParameter>, DefaultIgnore; def warn_decl_in_param_list : Warning< "declaration of %0 will not be visible outside of this function">; -def err_array_star_in_function_definition : Error< - "variable length array must be bound in function definition">; def warn_unused_function : Warning<"unused function %0">, InGroup<UnusedFunction>, DefaultIgnore; @@ -220,6 +236,12 @@ def err_object_cannot_be_passed_returned_by_value : Error< "interface type %1 cannot be %select{returned|passed}0 by value" "; did you forget * in %1">; def warn_enum_value_overflow : Warning<"overflow in enumeration value">; +def warn_pragma_options_align_unsupported_option : Warning< + "unsupported alignment option in '#pragma options align'">; +def warn_pragma_options_align_reset_failed : Warning< + "#pragma options align=reset failed: %0">; +def err_pragma_options_align_mac68k_target_unsupported : Error< + "mac68k alignment pragma is not supported on this target">; def warn_pragma_pack_invalid_alignment : Warning< "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">; // Follow the MSVC implementation. @@ -293,6 +315,8 @@ def warn_conflicting_ret_types : Warning< def warn_conflicting_param_types : Warning< "conflicting parameter types in implementation of %0: %1 vs %2">; +def warn_conflicting_variadic :Warning< + "conflicting variadic declaration of method and its implementation">; def warn_implements_nscopying : Warning< "default assign attribute on property %0 which implements " @@ -503,6 +527,10 @@ def err_access_copy_field : def err_access_copy_base : Error<"base class %0 has %select{private|protected}1 copy constructor">, NoSFINAE; +def err_access_dtor_ivar : + Error<"instance variable of type %0 has %select{private|protected}1 " + "destructor">, + NoSFINAE; def note_previous_access_declaration : Note< "previously declared '%1' here">; def err_access_outside_class : Error< @@ -709,6 +737,7 @@ def note_uninit_reference_member : Note< "uninitialized reference member is here">; def warn_field_is_uninit : Warning<"field is uninitialized when used here">, InGroup<DiagGroup<"uninitialized">>; +def err_init_incomplete_type : Error<"initialization of incomplete type %0">; def err_temp_copy_no_viable : Error< "no viable constructor %select{copying variable|copying parameter|" @@ -883,6 +912,12 @@ def warn_impcast_float_precision : Warning< def warn_impcast_float_integer : Warning< "implicit cast turns floating-point number into integer: %0 to %1">, InGroup<DiagGroup<"conversion">>, DefaultIgnore; +def warn_impcast_integer_sign : Warning< + "implicit cast changes signedness: %0 to %1">, + InGroup<DiagGroup<"conversion">>, DefaultIgnore; +def warn_impcast_integer_sign_conditional : Warning< + "operand of ? changes signedness: %0 to %1">, + InGroup<DiagGroup<"conversion">>, DefaultIgnore; def warn_impcast_integer_precision : Warning< "implicit cast loses integer precision: %0 to %1">, InGroup<DiagGroup<"conversion">>, DefaultIgnore; @@ -951,8 +986,7 @@ def err_attribute_regparm_invalid_number : Error< // Clang-Specific Attributes def err_attribute_iboutlet : Error< - "iboutlet attribute can only be applied to instance variables or " - "properties">; + "%0 attribute can only be applied to instance variables or properties">; def err_attribute_ibaction: Error< "ibaction attribute can only be applied to Objective-C instance methods">; def err_attribute_overloadable_not_function : Error< @@ -1054,15 +1088,29 @@ def note_ovl_candidate_bad_deduction : Note< "candidate template ignored: failed template argument deduction">; def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " "couldn't infer template argument %0">; - +def note_ovl_candidate_inconsistent_deduction : Note< + "candidate template ignored: deduced conflicting %select{types|values|" + "templates}0 for parameter %1 (%2 vs. %3)">; +def note_ovl_candidate_explicit_arg_mismatch_named : Note< + "candidate template ignored: invalid explicitly-specified argument " + "for template parameter %0">; +def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note< + "candidate template ignored: invalid explicitly-specified argument " + "for %ordinal0 template parameter">; +def note_ovl_candidate_instantiation_depth : Note< + "candidate template ignored: substitution exceeded maximum template " + "instantiation depth">; +def note_ovl_candidate_substitution_failure : Note< + "candidate template ignored: substitution failure %0">; + // Note that we don't treat templates differently for this diagnostic. def note_ovl_candidate_arity : Note<"candidate " "%select{function|function|constructor|function|function|constructor|" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" - "function (the implicit copy assignment operator)}0 not viable: requires" - "%select{ at least| at most|}2 %3 argument%s3, but %4 %plural{1:was|:were}4 " - "provided">; + "function (the implicit copy assignment operator)}0 %select{|template }1" + "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " + "%plural{1:was|:were}4 provided">; def note_ovl_candidate_deleted : Note< "candidate %select{function|function|constructor|" @@ -1484,6 +1532,12 @@ def err_explicit_instantiation_out_of_scope : Error< "explicit instantiation of %0 not in a namespace enclosing %1">; def err_explicit_instantiation_must_be_global : Error< "explicit instantiation of %0 must occur at global scope">; +def warn_explicit_instantiation_out_of_scope_0x : Warning< + "explicit instantiation of %0 not in a namespace enclosing %1">, + InGroup<DiagGroup<"-Wc++0x-compat"> >; +def warn_explicit_instantiation_must_be_global_0x : Warning< + "explicit instantiation of %0 must occur at global scope">, + InGroup<DiagGroup<"-Wc++0x-compat"> >; def err_explicit_instantiation_requires_name : Error< "explicit instantiation declaration requires a name">; @@ -1512,6 +1566,9 @@ def err_explicit_instantiation_without_qualified_id_quals : Error< "qualifier in explicit instantiation of '%0%1' requires a template-id">; def err_explicit_instantiation_unqualified_wrong_namespace : Error< "explicit instantiation of %q0 must occur in %1">; +def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning< + "explicit instantiation of %q0 must occur in %1">, + InGroup<DiagGroup<"c++0x-compat"> >; def err_explicit_instantiation_undefined_member : Error< "explicit instantiation of undefined %select{member class|member function|" "static data member}0 %1 of class template %2">; @@ -1631,12 +1688,6 @@ def warn_enumerator_too_large : Warning< def warn_illegal_constant_array_size : Extension< "size of static array must be an integer constant expression">; -def err_vla_decl_in_file_scope : Error< - "variable length array declaration not allowed at file scope">; -def err_vla_decl_has_static_storage : Error< - "variable length array declaration can not have 'static' storage duration">; -def err_vla_decl_has_extern_linkage : Error< - "variable length array declaration can not have 'extern' linkage">; def err_vm_decl_in_file_scope : Error< "variably modified type declaration not allowed at file scope">; def err_vm_decl_has_extern_linkage : Error< @@ -1725,20 +1776,20 @@ def err_undeclared_label_use : Error<"use of undeclared label '%0'">; def err_goto_into_protected_scope : Error<"illegal goto into protected scope">; def err_switch_into_protected_scope : Error< "illegal switch case into protected scope">; -def err_indirect_goto_in_protected_scope : Warning< - "illegal indirect goto in protected scope, unknown effect on scopes">, - InGroup<DiagGroup<"label-address-scope">>; -def err_addr_of_label_in_protected_scope : Warning< - "address taken of label in protected scope, jump to it would have " - "unknown effect on scope">, InGroup<DiagGroup<"label-address-scope">>; +def err_indirect_goto_without_addrlabel : Error< + "indirect goto in function with no address-of-label expressions">; +def warn_indirect_goto_in_protected_scope : Warning< + "indirect goto might cross protected scopes">, + InGroup<DiagGroup<"label-address-scope">>; +def note_indirect_goto_target : Note<"possible target of indirect goto">; def note_protected_by_variable_init : Note< "jump bypasses variable initialization">; +def note_protected_by_cleanup : Note< + "jump bypasses initialization of variable with __attribute__((cleanup))">; def note_protected_by_vla_typedef : Note< "jump bypasses initialization of VLA typedef">; def note_protected_by_vla : Note< "jump bypasses initialization of variable length array">; -def note_protected_by_cleanup : Note< - "jump bypasses initialization of declaration with __attribute__((cleanup))">; def note_protected_by_objc_try : Note< "jump bypasses initialization of @try block">; def note_protected_by_objc_catch : Note< @@ -1754,6 +1805,25 @@ def note_protected_by_cxx_catch : Note< def note_protected_by___block : Note< "jump bypasses setup of __block variable">; +def note_exits_cleanup : Note< + "jump exits scope of variable with __attribute__((cleanup))">; +def note_exits_dtor : Note< + "jump exits scope of variable with non-trivial destructor">; +def note_exits___block : Note< + "jump exits scope of __block variable">; +def note_exits_objc_try : Note< + "jump exits @try block">; +def note_exits_objc_catch : Note< + "jump exits @catch block">; +def note_exits_objc_finally : Note< + "jump exits @finally block">; +def note_exits_objc_synchronized : Note< + "jump exits @synchronized block">; +def note_exits_cxx_try : Note< + "jump exits try block">; +def note_exits_cxx_catch : Note< + "jump exits catch block">; + def err_func_returning_array_function : Error< "function cannot return %select{array|function}0 type %1">; def err_field_declared_as_function : Error<"field %0 declared as a function">; @@ -1764,6 +1834,8 @@ def ext_variable_sized_type_in_struct : ExtWarn< def err_flexible_array_empty_struct : Error< "flexible array %0 not allowed in otherwise empty struct">; +def err_flexible_array_has_nonpod_type : Error< + "flexible array member %0 of non-POD element type %1">; def ext_flexible_array_in_struct : Extension< "%0 may not be nested in a struct due to flexible array member">; def ext_flexible_array_in_array : Extension< @@ -1806,6 +1878,9 @@ def err_func_def_incomplete_result : Error< // Expressions. def ext_sizeof_function_type : Extension< "invalid application of 'sizeof' to a function type">, InGroup<PointerArith>; +def err_sizeof_alignof_overloaded_function_type : Error< + "invalid application of '%select{sizeof|__alignof}0' to an overloaded " + "function">; def ext_sizeof_void_type : Extension< "invalid application of '%0' to a void type">, InGroup<PointerArith>; def err_sizeof_alignof_incomplete_type : Error< @@ -2196,6 +2271,8 @@ def err_default_init_const : Error< "default initialization of an object of const type %0" "%select{| requires a user-provided default constructor}1">; def err_delete_operand : Error<"cannot delete expression of type %0">; +def ext_delete_void_ptr_operand : ExtWarn< + "cannot delete expression with pointer-to-'void' type %0">; def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete " "expression of type %0 to a pointer">; def warn_delete_incomplete : Warning< @@ -2293,7 +2370,9 @@ def err_cannot_form_pointer_to_member_of_reference_type : Error< "cannot form a pointer-to-member to member %0 of reference type %1">; def err_incomplete_object_call : Error< "incomplete type in call to object of type %0">; - +def err_incomplete_pointer_to_member_return : Error< + "incomplete return type %0 of pointer-to-member constant">; + def warn_condition_is_assignment : Warning<"using the result of an " "assignment as a condition without parentheses">, InGroup<Parentheses>; @@ -2510,31 +2589,35 @@ def warn_unused_call : Warning< def err_incomplete_type_used_in_type_trait_expr : Error< "incomplete type %0 used in type trait expression">; def err_expected_ident_or_lparen : Error<"expected identifier or '('">; - -// inline asm. -def err_asm_wide_character : Error<"wide string is invalid in 'asm'">; -def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; -def err_asm_invalid_output_constraint : Error< - "invalid output constraint '%0' in asm">; -def err_asm_invalid_lvalue_in_input : Error< - "invalid lvalue in asm input for constraint '%0'">; -def err_asm_invalid_input_constraint : Error< - "invalid input constraint '%0' in asm">; -def err_asm_invalid_type_in_input : Error< - "invalid type %0 in asm input for constraint '%1'">; -def err_asm_tying_incompatible_types : Error< - "unsupported inline asm: input with type %0 matching output with type %1">; -def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">; -def err_invalid_asm_cast_lvalue : Error< - "invalid use of a cast in a inline asm context requiring an l-value: " - "remove the cast or build with -fheinous-gnu-extensions">; - -def warn_invalid_asm_cast_lvalue : Warning< - "invalid use of a cast in a inline asm context requiring an l-value: " - "accepted due to -fheinous-gnu-extensions, but clang may remove support " - "for this in the future">; +} // End of general sema category. +// inline asm. +let CategoryName = "Inline Assembly Issue" in { + def err_asm_wide_character : Error<"wide string is invalid in 'asm'">; + def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; + def err_asm_invalid_output_constraint : Error< + "invalid output constraint '%0' in asm">; + def err_asm_invalid_lvalue_in_input : Error< + "invalid lvalue in asm input for constraint '%0'">; + def err_asm_invalid_input_constraint : Error< + "invalid input constraint '%0' in asm">; + def err_asm_invalid_type_in_input : Error< + "invalid type %0 in asm input for constraint '%1'">; + def err_asm_tying_incompatible_types : Error< + "unsupported inline asm: input with type %0 matching output with type %1">; + def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">; + def err_invalid_asm_cast_lvalue : Error< + "invalid use of a cast in a inline asm context requiring an l-value: " + "remove the cast or build with -fheinous-gnu-extensions">; + + def warn_invalid_asm_cast_lvalue : Warning< + "invalid use of a cast in a inline asm context requiring an l-value: " + "accepted due to -fheinous-gnu-extensions, but clang may remove support " + "for this in the future">; +} + +let CategoryName = "Semantic Issue" in { def err_invalid_conversion_between_vectors : Error< "invalid conversion between vector type %0 and %1 of different size">; @@ -2842,9 +2925,11 @@ def warn_case_value_overflow : Warning< InGroup<DiagGroup<"switch">>; def err_duplicate_case : Error<"duplicate case value '%0'">; def warn_case_empty_range : Warning<"empty case range specified">; +def warn_missing_case_for_condition : + Warning<"no case matching constant switch condition '%0'">; def warn_missing_cases : Warning<"enumeration value %0 not handled in switch">, InGroup<DiagGroup<"switch-enum"> >; -def not_in_enum : Warning<"case value not in enumerated type %0">, +def warn_not_in_enum : Warning<"case value not in enumerated type %0">, InGroup<DiagGroup<"switch-enum"> >; def err_typecheck_statement_requires_scalar : Error< "statement requires expression of scalar type (%0 invalid)">; @@ -3010,6 +3095,6 @@ def err_undeclared_protocol_suggest : Error< def note_base_class_specified_here : Note< "base class %0 specified here">; -} - +} // end of sema category +} // end of sema component. diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 930fb52873eb..6a4be4609433 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -280,6 +280,57 @@ public: /// \brief Read the source location entry with index ID. virtual void ReadSLocEntry(unsigned ID) = 0; }; + + +/// IsBeforeInTranslationUnitCache - This class holds the cache used by +/// isBeforeInTranslationUnit. The cache structure is complex enough to be +/// worth breaking out of SourceManager. +class IsBeforeInTranslationUnitCache { + /// L/R QueryFID - These are the FID's of the cached query. If these match up + /// with a subsequent query, the result can be reused. + FileID LQueryFID, RQueryFID; + + /// CommonFID - This is the file found in common between the two #include + /// traces. It is the nearest common ancestor of the #include tree. + FileID CommonFID; + + /// L/R CommonOffset - This is the offset of the previous query in CommonFID. + /// Usually, this represents the location of the #include for QueryFID, but if + /// LQueryFID is a parent of RQueryFID (or vise versa) then these can be a + /// random token in the parent. + unsigned LCommonOffset, RCommonOffset; +public: + + /// isCacheValid - Return true if the currently cached values match up with + /// the specified LHS/RHS query. If not, we can't use the cache. + bool isCacheValid(FileID LHS, FileID RHS) const { + return LQueryFID == LHS && RQueryFID == RHS; + } + + /// getCachedResult - If the cache is valid, compute the result given the + /// specified offsets in the LHS/RHS FID's. + bool getCachedResult(unsigned LOffset, unsigned ROffset) const { + // If one of the query files is the common file, use the offset. Otherwise, + // use the #include loc in the common file. + if (LQueryFID != CommonFID) LOffset = LCommonOffset; + if (RQueryFID != CommonFID) ROffset = RCommonOffset; + return LOffset < ROffset; + } + + // Set up a new query. + void setQueryFIDs(FileID LHS, FileID RHS) { + LQueryFID = LHS; + RQueryFID = RHS; + } + + void setCommonLoc(FileID commonFID, unsigned lCommonOffset, + unsigned rCommonOffset) { + CommonFID = commonFID; + LCommonOffset = lCommonOffset; + RCommonOffset = rCommonOffset; + } + +}; /// SourceManager - This file handles loading and caching of source files into /// memory. This object owns the MemoryBuffer objects for all of the loaded @@ -347,9 +398,7 @@ class SourceManager { mutable unsigned NumLinearScans, NumBinaryProbes; // Cache results for the isBeforeInTranslationUnit method. - mutable FileID LastLFIDForBeforeTUCheck; - mutable FileID LastRFIDForBeforeTUCheck; - mutable bool LastResForBeforeTUCheck; + mutable IsBeforeInTranslationUnitCache IsBeforeInTUCache; // SourceManager doesn't support copy construction. explicit SourceManager(const SourceManager&); diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 19987508baf3..00fd9b92e13e 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -58,6 +58,8 @@ protected: const llvm::fltSemantics *FloatFormat, *DoubleFormat, *LongDoubleFormat; unsigned char RegParmMax, SSERegParmMax; + unsigned HasAlignMac68kSupport : 1; + // TargetInfo Constructor. Default initializes all fields. TargetInfo(const std::string &T); @@ -210,6 +212,12 @@ public: return UseBitFieldTypeAlignment; } + /// hasAlignMac68kSupport - Check whether this target support '#pragma options + /// align=mac68k'. + bool hasAlignMac68kSupport() const { + return HasAlignMac68kSupport; + } + /// getTypeName - Return the user string for the specified integer type enum. /// For example, SignedShort -> "short". static const char *getTypeName(IntType T); diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 52e83f4045ef..b16b82854b1c 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -220,7 +220,7 @@ KEYWORD(unsigned , KEYALL) KEYWORD(void , KEYALL) KEYWORD(volatile , KEYALL) KEYWORD(while , KEYALL) -KEYWORD(_Bool , KEYALL) +KEYWORD(_Bool , KEYNOMS) KEYWORD(_Complex , KEYALL) KEYWORD(_Imaginary , KEYALL) KEYWORD(__func__ , KEYALL) @@ -336,6 +336,7 @@ KEYWORD(__declspec , KEYALL) KEYWORD(__cdecl , KEYALL) KEYWORD(__stdcall , KEYALL) KEYWORD(__fastcall , KEYALL) +KEYWORD(__thiscall , KEYALL) KEYWORD(__forceinline , KEYALL) // Altivec Extension. @@ -372,6 +373,7 @@ ALIAS("_asm" , asm , KEYMS) ALIAS("_cdecl" , __cdecl , KEYMS) ALIAS("_fastcall" , __fastcall , KEYMS) ALIAS("_stdcall" , __stdcall , KEYMS) +ALIAS("_thiscall" , __thiscall , KEYMS) //===----------------------------------------------------------------------===// // Objective-C @-preceeded keywords. diff --git a/include/clang/CMakeLists.txt b/include/clang/CMakeLists.txt index 61d2bf602d9a..c2880481a2e9 100644 --- a/include/clang/CMakeLists.txt +++ b/include/clang/CMakeLists.txt @@ -1,2 +1,3 @@ +add_subdirectory(AST) add_subdirectory(Basic) add_subdirectory(Driver) diff --git a/include/clang/Checker/PathSensitive/AnalysisManager.h b/include/clang/Checker/PathSensitive/AnalysisManager.h index 0c59d7b572a4..3c7cb68c0943 100644 --- a/include/clang/Checker/PathSensitive/AnalysisManager.h +++ b/include/clang/Checker/PathSensitive/AnalysisManager.h @@ -37,8 +37,12 @@ class AnalysisManager : public BugReporterData { enum AnalysisScope { ScopeTU, ScopeDecl } AScope; + // The maximum number of exploded nodes the analyzer will generate. unsigned MaxNodes; + // The maximum number of times the analyzer will go through a loop. + unsigned MaxLoop; + bool VisualizeEGDot; bool VisualizeEGUbi; bool PurgeDead; @@ -52,19 +56,22 @@ class AnalysisManager : public BugReporterData { // bifurcates paths. bool EagerlyAssume; bool TrimGraph; + bool InlineCall; public: AnalysisManager(ASTContext &ctx, Diagnostic &diags, const LangOptions &lang, PathDiagnosticClient *pd, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, unsigned maxnodes, - bool vizdot, bool vizubi, bool purge, bool eager, bool trim) + unsigned maxloop, + bool vizdot, bool vizubi, bool purge, bool eager, bool trim, + bool inlinecall) : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), - AScope(ScopeDecl), MaxNodes(maxnodes), + AScope(ScopeDecl), MaxNodes(maxnodes), MaxLoop(maxloop), VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), - EagerlyAssume(eager), TrimGraph(trim) {} + EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall) {} ~AnalysisManager() { FlushDiagnostics(); } @@ -108,6 +115,8 @@ public: unsigned getMaxNodes() const { return MaxNodes; } + unsigned getMaxLoop() const { return MaxLoop; } + bool shouldVisualizeGraphviz() const { return VisualizeEGDot; } bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; } @@ -122,6 +131,8 @@ public: bool shouldEagerlyAssume() const { return EagerlyAssume; } + bool shouldInlineCall() const { return InlineCall; } + CFG *getCFG(Decl const *D) { return AnaCtxMgr.getContext(D)->getCFG(); } diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h index f04ca75084b7..ac407f6933c8 100644 --- a/include/clang/Checker/PathSensitive/GRExprEngine.h +++ b/include/clang/Checker/PathSensitive/GRExprEngine.h @@ -456,6 +456,8 @@ private: void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred, const GRState* St, SVal location, const void *tag, bool isLoad); + + bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred); }; } // end clang namespace diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h index 41d7c2bd713e..f3155b9aacd4 100644 --- a/include/clang/Checker/PathSensitive/Store.h +++ b/include/clang/Checker/PathSensitive/Store.h @@ -18,6 +18,7 @@ #include "clang/Checker/PathSensitive/SVals.h" #include "clang/Checker/PathSensitive/ValueManager.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" namespace clang { @@ -143,9 +144,9 @@ public: return UnknownVal(); } - virtual Store RemoveDeadBindings(Store store, Stmt* Loc, - const StackFrameContext *LCtx, - SymbolReaper& SymReaper, + virtual const GRState *RemoveDeadBindings(GRState &state, Stmt* Loc, + const StackFrameContext *LCtx, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0; virtual Store BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0; @@ -167,10 +168,15 @@ public: // FIXME: Make out-of-line. virtual const GRState *setExtent(const GRState *state, - const MemRegion *region, SVal extent) { + const MemRegion *region, SVal extent) { return state; } + virtual llvm::Optional<SVal> getExtent(const GRState *state, + const MemRegion *R) { + return llvm::Optional<SVal>(); + } + /// EnterStackFrame - Let the StoreManager to do something when execution /// engine is about to execute into a callee. virtual const GRState *EnterStackFrame(const GRState *state, diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h index 54d3ba03f3f0..6241230ffb45 100644 --- a/include/clang/CodeGen/CodeGenOptions.h +++ b/include/clang/CodeGen/CodeGenOptions.h @@ -54,6 +54,7 @@ public: unsigned ObjCDispatchMethod : 2; /// Method of Objective-C dispatch to use. unsigned OptimizationLevel : 3; /// The -O[0-4] option specified. unsigned OptimizeSize : 1; /// If -Os is specified. + unsigned RelaxAll : 1; /// Relax all machine code instructions. unsigned SoftFloat : 1; /// -soft-float. unsigned TimePasses : 1; /// Set when -ftime-report is enabled. unsigned UnitAtATime : 1; /// Unused. For mirroring GCC optimization @@ -108,6 +109,7 @@ public: ObjCDispatchMethod = Legacy; OptimizationLevel = 0; OptimizeSize = 0; + RelaxAll = 0; SoftFloat = 0; TimePasses = 0; UnitAtATime = 1; diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h index 0a8eaeaf238f..7a14ae84d466 100644 --- a/include/clang/Driver/ArgList.h +++ b/include/clang/Driver/ArgList.h @@ -17,12 +17,15 @@ #include <list> #include <string> +#include <vector> namespace llvm { class Twine; } namespace clang { + class Diagnostic; + namespace driver { class Arg; class ArgList; @@ -175,6 +178,25 @@ namespace driver { /// getArgString - Return the input argument string at \arg Index. virtual const char *getArgString(unsigned Index) const = 0; + + /// @} + /// @name Argument Lookup Utilities + /// @{ + + /// getLastArgValue - Return the value of the last argument, or a default. + llvm::StringRef getLastArgValue(OptSpecifier Id, + llvm::StringRef Default = "") const; + + /// getLastArgValue - Return the value of the last argument as an integer, + /// or a default. Emits an error if the argument is given, but non-integral. + int getLastArgIntValue(OptSpecifier Id, int Default, + Diagnostic &Diags) const; + + /// getAllArgValues - Get the values of all instances of the given argument + /// as strings. + std::vector<std::string> getAllArgValues(OptSpecifier Id) const; + + /// @} /// @name Translation Utilities /// @{ diff --git a/include/clang/Driver/CC1AsOptions.h b/include/clang/Driver/CC1AsOptions.h new file mode 100644 index 000000000000..05082132cee4 --- /dev/null +++ b/include/clang/Driver/CC1AsOptions.h @@ -0,0 +1,32 @@ +//===--- CC1AsOptions.h - Clang Assembler Options Table ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_CC1ASOPTIONS_H +#define CLANG_DRIVER_CC1ASOPTIONS_H + +namespace clang { +namespace driver { + class OptTable; + +namespace cc1asoptions { + enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) OPT_##ID, +#include "clang/Driver/CC1AsOptions.inc" + LastOption +#undef OPTION + }; +} + + OptTable *createCC1AsOptTable(); +} +} + +#endif diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td new file mode 100644 index 000000000000..5c08dc630551 --- /dev/null +++ b/include/clang/Driver/CC1AsOptions.td @@ -0,0 +1,71 @@ +//===--- CC1AsOptions.td - Options for clang -cc1as -----------------------===// +// +// 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 options accepted by clang -cc1as. +// +//===----------------------------------------------------------------------===// + +// Include the common option parsing interfaces. +include "OptParser.td" + +//===----------------------------------------------------------------------===// +// Target Options +//===----------------------------------------------------------------------===// + +def triple : Separate<"-triple">, + HelpText<"Specify target triple (e.g. x86_64-pc-linux-gnu)">; + +//===----------------------------------------------------------------------===// +// Language Options +//===----------------------------------------------------------------------===// + +def I : JoinedOrSeparate<"-I">, MetaVarName<"<directory>">, + HelpText<"Add directory to include search path">; +def n : Flag<"-n">, + HelpText<"Don't automatically start assembly file with a text section">; + +//===----------------------------------------------------------------------===// +// Frontend Options +//===----------------------------------------------------------------------===// + +def o : Separate<"-o">, MetaVarName<"<path>">, HelpText<"Specify output file">; + +def filetype : Separate<"-filetype">, + HelpText<"Specify the output file type ('asm', 'null', or 'obj')">; + +def help : Flag<"-help">, + HelpText<"Print this help text">; +def _help : Flag<"--help">, Alias<help>; + +def version : Flag<"-version">, + HelpText<"Print the assembler version">; +def _version : Flag<"--version">, Alias<version>; + +// Generic forwarding to LLVM options. This should only be used for debugging +// and experimental features. +def mllvm : Separate<"-mllvm">, + HelpText<"Additional arguments to forward to LLVM's option processing">; + +//===----------------------------------------------------------------------===// +// Transliterate Options +//===----------------------------------------------------------------------===// + +def output_asm_variant : Separate<"-output-asm-variant">, + HelpText<"Select the asm variant index to use for output">; +def show_encoding : Flag<"-show-encoding">, + HelpText<"Show instruction encoding information in transliterate mode">; +def show_inst : Flag<"-show-inst">, + HelpText<"Show internal instruction representation in transliterate mode">; + +//===----------------------------------------------------------------------===// +// Assemble Options +//===----------------------------------------------------------------------===// + +def relax_all : Flag<"-relax-all">, + HelpText<"Relax all fixups (for performance testing)">; diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 0badeb9efa54..fd8322b84370 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -56,8 +56,6 @@ def analysis_ObjCMemChecker : Flag<"-analyzer-check-objc-mem">, HelpText<"Run the [Core] Foundation reference count checker">; def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">, HelpText<"Warn about unintended use of sizeof() on pointer expressions">; -def analysis_InlineCall : Flag<"-inline-call">, - HelpText<"Experimental transfer function inlining callees when its definition is available.">; def analyzer_store : Separate<"-analyzer-store">, HelpText<"Source Code Analysis - Abstract Memory Store Models">; @@ -97,8 +95,12 @@ def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">, HelpText<"Display exploded graph using GraphViz">; def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">, HelpText<"Display exploded graph using Ubigraph">; +def analyzer_inline_call : Flag<"-analyzer-inline-call">, + HelpText<"Experimental transfer function inlining callees when its definition is available.">; def analyzer_max_nodes : Separate<"-analyzer-max-nodes">, HelpText<"The maximum number of nodes the analyzer can generate">; +def analyzer_max_loop : Separate<"-analyzer-max-loop">, + HelpText<"The maximum number of times the analyzer will go through a loop">; //===----------------------------------------------------------------------===// // CodeGen Options @@ -145,6 +147,8 @@ def mno_zero_initialized_in_bss : Flag<"-mno-zero-initialized-in-bss">, HelpText<"Do not put zero initialized data in the BSS">; def msoft_float : Flag<"-msoft-float">, HelpText<"Use software floating point">; +def mrelax_all : Flag<"-mrelax-all">, + HelpText<"Relax all machine instructions">; def mrelocation_model : Separate<"-mrelocation-model">, HelpText<"The relocation model to use">; def munwind_tables : Flag<"-munwind-tables">, @@ -196,6 +200,9 @@ def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-rang HelpText<"Print source range spans in numeric form">; def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, HelpText<"Print diagnostic name with mappable diagnostics">; +def fdiagnostics_show_category : Separate<"-fdiagnostics-show-category">, + HelpText<"Print diagnostic category">; + def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">, HelpText<"Set the tab stop distance.">; def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">, @@ -238,6 +245,8 @@ def no_code_completion_debug_printer : Flag<"-no-code-completion-debug-printer"> HelpText<"Don't use the \"debug\" code-completion print">; def code_completion_macros : Flag<"-code-completion-macros">, HelpText<"Include macros in code-completion results">; +def code_completion_patterns : Flag<"-code-completion-patterns">, + HelpText<"Include code patterns in code-completion results">; def disable_free : Flag<"-disable-free">, HelpText<"Disable freeing of memory on exit">; def help : Flag<"-help">, @@ -293,6 +302,8 @@ def ast_dump : Flag<"-ast-dump">, HelpText<"Build ASTs and then debug dump them">; def ast_view : Flag<"-ast-view">, HelpText<"Build ASTs and view them with GraphViz">; +def boostcon : Flag<"-boostcon">, + HelpText<"BoostCon workshop mode">; def print_decl_contexts : Flag<"-print-decl-contexts">, HelpText<"Print DeclContexts and their Decls">; def emit_pth : Flag<"-emit-pth">, @@ -307,6 +318,8 @@ def emit_llvm_bc : Flag<"-emit-llvm-bc">, HelpText<"Build ASTs then convert to LLVM, emit .bc file">; def emit_llvm_only : Flag<"-emit-llvm-only">, HelpText<"Build ASTs and convert to LLVM, discarding output">; +def emit_codegen_only : Flag<"-emit-codegen-only">, + HelpText<"Generate machine code, but discard output">; def emit_obj : Flag<"-emit-obj">, HelpText<"Emit native object files">; def rewrite_test : Flag<"-rewrite-test">, diff --git a/include/clang/Driver/CMakeLists.txt b/include/clang/Driver/CMakeLists.txt index ed9825b59df5..99be53ffc72b 100644 --- a/include/clang/Driver/CMakeLists.txt +++ b/include/clang/Driver/CMakeLists.txt @@ -9,3 +9,9 @@ tablegen(CC1Options.inc -gen-opt-parser-defs) add_custom_target(ClangCC1Options DEPENDS CC1Options.inc) + +set(LLVM_TARGET_DEFINITIONS CC1AsOptions.td) +tablegen(CC1AsOptions.inc + -gen-opt-parser-defs) +add_custom_target(ClangCC1AsOptions + DEPENDS CC1AsOptions.inc) diff --git a/include/clang/Driver/Makefile b/include/clang/Driver/Makefile index 18f3e58d7db4..b462aaa24bc9 100644 --- a/include/clang/Driver/Makefile +++ b/include/clang/Driver/Makefile @@ -1,5 +1,5 @@ LEVEL = ../../../../.. -BUILT_SOURCES = Options.inc CC1Options.inc +BUILT_SOURCES = Options.inc CC1Options.inc CC1AsOptions.inc TABLEGEN_INC_FILES_COMMON = 1 @@ -13,4 +13,6 @@ $(ObjDir)/CC1Options.inc.tmp : CC1Options.td OptParser.td $(TBLGEN) $(ObjDir)/.d $(Echo) "Building Clang CC1 Option tables with tblgen" $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $< - +$(ObjDir)/CC1AsOptions.inc.tmp : CC1AsOptions.td OptParser.td $(TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang CC1 Assembler Option tables with tblgen" + $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $< diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index f6e69e045444..a9a52c01f45b 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -139,6 +139,7 @@ def MQ : JoinedOrSeparate<"-MQ">, Group<M_Group>; def MT : JoinedOrSeparate<"-MT">, Group<M_Group>; def Mach : Flag<"-Mach">; def M : Flag<"-M">, Group<M_Group>; +def O0 : Joined<"-O0">, Group<O_Group>; def O4 : Joined<"-O4">, Group<O_Group>; def ObjCXX : Flag<"-ObjC++">, Flags<[DriverOption]>, HelpText<"Treat source input files as Objective-C++ inputs">; @@ -231,6 +232,7 @@ def fPIC : Flag<"-fPIC">, Group<f_Group>; def fPIE : Flag<"-fPIE">, Group<f_Group>; def faccess_control : Flag<"-faccess-control">, Group<f_Group>; def fapple_kext : Flag<"-fapple-kext">, Group<f_Group>; +def fasm : Flag<"-fasm">, Group<f_Group>; def fasm_blocks : Flag<"-fasm-blocks">, Group<clang_ignored_f_Group>; def fassume_sane_operator_new : Flag<"-fassume-sane-operator-new">, Group<f_Group>; def fastcp : Flag<"-fastcp">, Group<f_Group>; @@ -257,6 +259,7 @@ def fdiagnostics_binary : Flag<"-fdiagnostics-binary">, Group<f_Group>, Flags<[H def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group<f_Group>; def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group<f_Group>; def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>; +def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_Group>; def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>; def feliminate_unused_debug_symbols : Flag<"-feliminate-unused-debug-symbols">, Group<f_Group>; def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>; @@ -265,10 +268,7 @@ def fexceptions : Flag<"-fexceptions">, Group<f_Group>; def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>; def fhosted : Flag<"-fhosted">, Group<f_Group>; def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>; - def fgnu_keywords : Flag<"-fgnu-keywords">, Group<f_Group>; -def fasm : Flag<"-fasm">, Alias<fgnu_keywords>; - def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>; def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; def filelist : Separate<"-filelist">, Flags<[LinkerInput]>; @@ -291,6 +291,7 @@ def fmudflap : Flag<"-fmudflap">, Group<f_Group>; def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>; def fnext_runtime : Flag<"-fnext-runtime">, Group<f_Group>; def fno_access_control : Flag<"-fno-access-control">, Group<f_Group>; +def fno_asm : Flag<"-fno-asm">, Group<f_Group>; def fno_asynchronous_unwind_tables : Flag<"-fno-asynchronous-unwind-tables">, Group<f_Group>; def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, Group<f_Group>; def fno_blocks : Flag<"-fno-blocks">, Group<f_Group>; @@ -306,10 +307,7 @@ def fno_diagnostics_show_option : Flag<"-fno-diagnostics-show-option">, Group<f_ def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, Group<f_Group>; def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group<f_Group>; def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>; - def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, Group<f_Group>; -def fno_asm : Flag<"-fno-asm">, Alias<fno_gnu_keywords>; - def fno_inline_functions : Flag<"-fno-inline-functions">, Group<clang_ignored_f_Group>; def fno_inline : Flag<"-fno-inline">, Group<clang_ignored_f_Group>; def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_ignored_f_Group>; @@ -329,6 +327,7 @@ def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group<f_Group>; def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>; def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group<f_Group>; def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>; +def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group<f_Group>; def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>; def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>; def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>; @@ -384,6 +383,8 @@ def fverbose_asm : Flag<"-fverbose-asm">, Group<f_Group>; def fvisibility_EQ : Joined<"-fvisibility=">, Group<f_Group>; def fwritable_strings : Flag<"-fwritable-strings">, Group<f_Group>; def fzero_initialized_in_bss : Flag<"-fzero-initialized-in-bss">, Group<f_Group>; +def ffunction_sections: Flag <"-ffunction-sections">, Group<f_Group>; +def fdata_sections : Flag <"-fdata-sections">, Group<f_Group>; def f : Joined<"-f">, Group<f_Group>; def g0 : Joined<"-g0">, Group<g_Group>; def g3 : Joined<"-g3">, Group<g_Group>; @@ -436,6 +437,7 @@ def mno_constant_cfstrings : Flag<"-mno-constant-cfstrings">, Group<m_Group>; def mno_mmx : Flag<"-mno-mmx">, Group<m_x86_Features_Group>; def mno_pascal_strings : Flag<"-mno-pascal-strings">, Group<m_Group>; def mno_red_zone : Flag<"-mno-red-zone">, Group<m_Group>; +def mno_relax_all : Flag<"-mno-relax-all">, Group<m_Group>; def mno_soft_float : Flag<"-mno-soft-float">, Group<m_Group>; def mno_sse2 : Flag<"-mno-sse2">, Group<m_x86_Features_Group>; def mno_sse3 : Flag<"-mno-sse3">, Group<m_x86_Features_Group>; @@ -453,6 +455,7 @@ def marm : Flag<"-marm">, Alias<mno_thumb>; def mno_warn_nonportable_cfstrings : Flag<"-mno-warn-nonportable-cfstrings">, Group<m_Group>; def mpascal_strings : Flag<"-mpascal-strings">, Group<m_Group>; def mred_zone : Flag<"-mred-zone">, Group<m_Group>; +def mrelax_all : Flag<"-mrelax-all">, Group<m_Group>; def msoft_float : Flag<"-msoft-float">, Group<m_Group>; def msse2 : Flag<"-msse2">, Group<m_x86_Features_Group>; def msse3 : Flag<"-msse3">, Group<m_x86_Features_Group>; @@ -667,6 +670,7 @@ def _pipe : Flag<"--pipe">, Alias<pipe>, Flags<[DriverOption]>; def _prefix_EQ : Joined<"--prefix=">, Alias<B>, Flags<[RenderSeparate]>; def _prefix : Separate<"--prefix">, Alias<B>; def _preprocess : Flag<"--preprocess">, Alias<E>; +def _print_diagnostic_categories : Flag<"--print-diagnostic-categories">; def _print_file_name_EQ : Joined<"--print-file-name=">, Alias<print_file_name_EQ>; def _print_file_name : Separate<"--print-file-name">, Alias<print_file_name_EQ>; def _print_libgcc_file_name : Flag<"--print-libgcc-file-name">, Alias<print_libgcc_file_name>; diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h index ef77206c6593..4368a81e3a41 100644 --- a/include/clang/Driver/Tool.h +++ b/include/clang/Driver/Tool.h @@ -30,17 +30,23 @@ class Tool { /// The tool name (for debugging). const char *Name; + /// The human readable name for the tool, for use in diagnostics. + const char *ShortName; + /// The tool chain this tool is a part of. const ToolChain &TheToolChain; public: - Tool(const char *Name, const ToolChain &TC); + Tool(const char *Name, const char *ShortName, + const ToolChain &TC); public: virtual ~Tool(); const char *getName() const { return Name; } + const char *getShortName() const { return ShortName; } + const ToolChain &getToolChain() const { return TheToolChain; } virtual bool acceptsPipedInput() const = 0; diff --git a/include/clang/Frontend/AnalysisConsumer.h b/include/clang/Frontend/AnalysisConsumer.h index 3341bb01f0fa..2cbdf368a893 100644 --- a/include/clang/Frontend/AnalysisConsumer.h +++ b/include/clang/Frontend/AnalysisConsumer.h @@ -61,6 +61,7 @@ public: AnalysisDiagClients AnalysisDiagOpt; std::string AnalyzeSpecificFunction; unsigned MaxNodes; + unsigned MaxLoop; unsigned AnalyzeAll : 1; unsigned AnalyzerDisplayProgress : 1; unsigned AnalyzeNestedBlocks : 1; @@ -71,6 +72,8 @@ public: unsigned VisualizeEGUbi : 1; unsigned EnableExperimentalChecks : 1; unsigned EnableExperimentalInternalChecks : 1; + unsigned InlineCall : 1; + public: AnalyzerOptions() { AnalysisStoreOpt = BasicStoreModel; diff --git a/include/clang/Frontend/CodeGenAction.h b/include/clang/Frontend/CodeGenAction.h index a1e3c42075b6..dfc117a0b06c 100644 --- a/include/clang/Frontend/CodeGenAction.h +++ b/include/clang/Frontend/CodeGenAction.h @@ -57,6 +57,11 @@ public: EmitLLVMOnlyAction(); }; +class EmitCodeGenOnlyAction : public CodeGenAction { +public: + EmitCodeGenOnlyAction(); +}; + class EmitObjAction : public CodeGenAction { public: EmitObjAction(); diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index 36720c9d1462..06dc8004a652 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -519,7 +519,7 @@ public: createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename, unsigned Line, unsigned Column, bool UseDebugPrinter, bool ShowMacros, - llvm::raw_ostream &OS); + bool ShowCodePatterns, llvm::raw_ostream &OS); /// Create the frontend timer and replace any existing one with it. void createFrontendTimer(); diff --git a/include/clang/Frontend/DeclXML.def b/include/clang/Frontend/DeclXML.def index e839a8c4c772..16551ee03e1f 100644 --- a/include/clang/Frontend/DeclXML.def +++ b/include/clang/Frontend/DeclXML.def @@ -84,6 +84,7 @@ NODE_XML(Decl, "FIXME_Decl") ATTRIBUTE_FILE_LOCATION_XML + ATTRIBUTE_XML(getDeclKindName(), "unhandled_decl_name") END_NODE_XML NODE_XML(FunctionDecl, "Function") @@ -106,7 +107,7 @@ NODE_XML(FunctionDecl, "Function") SUB_NODE_FN_BODY_XML END_NODE_XML -NODE_XML(CXXMethodDecl, "CXXMethodDecl") +NODE_XML(CXXMethodDecl, "CXXMethod") ID_ATTRIBUTE_XML ATTRIBUTE_FILE_LOCATION_XML ATTRIBUTE_XML(getDeclContext(), "context") @@ -116,6 +117,79 @@ NODE_XML(CXXMethodDecl, "CXXMethodDecl") ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") ATTRIBUTE_OPT_XML(isStatic(), "static") ATTRIBUTE_OPT_XML(isVirtual(), "virtual") + ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access") + ENUM_XML(AS_none, "") + ENUM_XML(AS_public, "public") + ENUM_XML(AS_protected, "protected") + ENUM_XML(AS_private, "private") + END_ENUM_XML + ATTRIBUTE_XML(getNumParams(), "num_args") + SUB_NODE_SEQUENCE_XML(ParmVarDecl) + SUB_NODE_FN_BODY_XML +END_NODE_XML + +NODE_XML(CXXConstructorDecl, "CXXConstructor") + ID_ATTRIBUTE_XML + ATTRIBUTE_FILE_LOCATION_XML + ATTRIBUTE_XML(getDeclContext(), "context") + ATTRIBUTE_XML(getNameAsString(), "name") + TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType()) + ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type") + ATTRIBUTE_OPT_XML(isExplicit(), "is_explicit") + ATTRIBUTE_OPT_XML(isDefaultConstructor(), "is_default_ctor") + ATTRIBUTE_OPT_XML(isCopyConstructor(), "is_copy_ctor") + ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") + ATTRIBUTE_OPT_XML(isStatic(), "static") + ATTRIBUTE_OPT_XML(isVirtual(), "virtual") + ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access") + ENUM_XML(AS_none, "") + ENUM_XML(AS_public, "public") + ENUM_XML(AS_protected, "protected") + ENUM_XML(AS_private, "private") + END_ENUM_XML + ATTRIBUTE_XML(getNumParams(), "num_args") + SUB_NODE_SEQUENCE_XML(ParmVarDecl) + SUB_NODE_FN_BODY_XML +END_NODE_XML + +NODE_XML(CXXDestructorDecl, "CXXDestructor") + ID_ATTRIBUTE_XML + ATTRIBUTE_FILE_LOCATION_XML + ATTRIBUTE_XML(getDeclContext(), "context") + ATTRIBUTE_XML(getNameAsString(), "name") + TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType()) + ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type") + ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") + ATTRIBUTE_OPT_XML(isStatic(), "static") + ATTRIBUTE_OPT_XML(isVirtual(), "virtual") + ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access") + ENUM_XML(AS_none, "") + ENUM_XML(AS_public, "public") + ENUM_XML(AS_protected, "protected") + ENUM_XML(AS_private, "private") + END_ENUM_XML + ATTRIBUTE_XML(getNumParams(), "num_args") + SUB_NODE_SEQUENCE_XML(ParmVarDecl) + SUB_NODE_FN_BODY_XML +END_NODE_XML + +NODE_XML(CXXConversionDecl, "CXXConversion") + ID_ATTRIBUTE_XML + ATTRIBUTE_FILE_LOCATION_XML + ATTRIBUTE_XML(getDeclContext(), "context") + ATTRIBUTE_XML(getNameAsString(), "name") + TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType()) + ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type") + ATTRIBUTE_OPT_XML(isExplicit(), "is_explicit") + ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") + ATTRIBUTE_OPT_XML(isStatic(), "static") + ATTRIBUTE_OPT_XML(isVirtual(), "virtual") + ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access") + ENUM_XML(AS_none, "") + ENUM_XML(AS_public, "public") + ENUM_XML(AS_protected, "protected") + ENUM_XML(AS_private, "private") + END_ENUM_XML ATTRIBUTE_XML(getNumParams(), "num_args") SUB_NODE_SEQUENCE_XML(ParmVarDecl) SUB_NODE_FN_BODY_XML @@ -126,6 +200,7 @@ NODE_XML(NamespaceDecl, "Namespace") ATTRIBUTE_FILE_LOCATION_XML ATTRIBUTE_XML(getDeclContext(), "context") ATTRIBUTE_XML(getNameAsString(), "name") + SUB_NODE_SEQUENCE_XML(DeclContext) END_NODE_XML NODE_XML(UsingDirectiveDecl, "UsingDirective") @@ -189,6 +264,12 @@ NODE_XML(FieldDecl, "Field") ATTRIBUTE_XML(getNameAsString(), "name") TYPE_ATTRIBUTE_XML(getType()) ATTRIBUTE_OPT_XML(isMutable(), "mutable") + ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access") + ENUM_XML(AS_none, "") + ENUM_XML(AS_public, "public") + ENUM_XML(AS_protected, "protected") + ENUM_XML(AS_private, "private") + END_ENUM_XML ATTRIBUTE_OPT_XML(isBitField(), "bitfield") SUB_NODE_OPT_XML(Expr) // init expr of a bit field END_NODE_XML @@ -237,6 +318,35 @@ NODE_XML(LinkageSpecDecl, "LinkageSpec") END_ENUM_XML END_NODE_XML +NODE_XML(TemplateDecl, "Template") + ID_ATTRIBUTE_XML + ATTRIBUTE_FILE_LOCATION_XML + ATTRIBUTE_XML(getDeclContext(), "context") + ATTRIBUTE_XML(getNameAsString(), "name") +END_NODE_XML + +NODE_XML(TemplateTypeParmDecl, "TemplateTypeParm") + ID_ATTRIBUTE_XML + ATTRIBUTE_FILE_LOCATION_XML + ATTRIBUTE_XML(getDeclContext(), "context") + ATTRIBUTE_XML(getNameAsString(), "name") +END_NODE_XML + +NODE_XML(UsingShadowDecl, "UsingShadow") + ID_ATTRIBUTE_XML + ATTRIBUTE_FILE_LOCATION_XML + ATTRIBUTE_XML(getDeclContext(), "context") + ATTRIBUTE_XML(getTargetDecl(), "target_decl") + ATTRIBUTE_XML(getUsingDecl(), "using_decl") +END_NODE_XML + +NODE_XML(UsingDecl, "Using") + ID_ATTRIBUTE_XML + ATTRIBUTE_FILE_LOCATION_XML + ATTRIBUTE_XML(getDeclContext(), "context") + ATTRIBUTE_XML(getTargetNestedNameDecl(), "target_nested_namespace_decl") + ATTRIBUTE_XML(isTypeName(), "is_typename") +END_NODE_XML //===----------------------------------------------------------------------===// #undef NODE_XML diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h index b4f147bde7b7..8eb66e57da92 100644 --- a/include/clang/Frontend/DiagnosticOptions.h +++ b/include/clang/Frontend/DiagnosticOptions.h @@ -30,6 +30,8 @@ public: unsigned ShowSourceRanges : 1; /// Show source ranges in numeric form. unsigned ShowOptionNames : 1; /// Show the diagnostic name for mappable /// diagnostics. + unsigned ShowCategories : 2; /// Show categories: 0 -> none, 1 -> Number, + /// 2 -> Full Name. unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences. unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected /// diagnostics, indicated by markers in the @@ -74,12 +76,13 @@ public: ShowFixits = 1; ShowLocation = 1; ShowOptionNames = 0; + ShowCategories = 0; ShowSourceRanges = 0; VerifyDiagnostics = 0; BinaryOutput = 0; ErrorLimit = 0; - TemplateBacktraceLimit = 0; - MacroBacktraceLimit = 0; + TemplateBacktraceLimit = DefaultTemplateBacktraceLimit; + MacroBacktraceLimit = DefaultMacroBacktraceLimit; } }; diff --git a/include/clang/Frontend/DocumentXML.h b/include/clang/Frontend/DocumentXML.h index 6693ddbac57d..73d892105f21 100644 --- a/include/clang/Frontend/DocumentXML.h +++ b/include/clang/Frontend/DocumentXML.h @@ -114,6 +114,7 @@ private: void addPtrAttribute(const char* pName, const NamedDecl* D); void addPtrAttribute(const char* pName, const DeclContext* D); void addPtrAttribute(const char* pName, const NamespaceDecl* D); // disambiguation + void addPtrAttribute(const char* pName, const NestedNameSpecifier* N); void addPtrAttribute(const char* pName, const LabelStmt* L); void addPtrAttribute(const char* pName, const char* text); @@ -145,12 +146,23 @@ inline void DocumentXML::initialize(ASTContext &Context) { //--------------------------------------------------------- template<class T> inline void DocumentXML::addAttribute(const char* pName, const T& value) { - Out << ' ' << pName << "=\"" << value << "\""; + std::string repr; + { + llvm::raw_string_ostream buf(repr); + buf << value; + buf.flush(); + } + + Out << ' ' << pName << "=\"" + << DocumentXML::escapeString(repr.c_str(), repr.size()) + << "\""; } //--------------------------------------------------------- inline void DocumentXML::addPtrAttribute(const char* pName, const char* text) { - Out << ' ' << pName << "=\"" << text << "\""; + Out << ' ' << pName << "=\"" + << DocumentXML::escapeString(text, strlen(text)) + << "\""; } //--------------------------------------------------------- diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index 3ddd77dc39e0..cee1c1d2be77 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -75,12 +75,10 @@ protected: }; class FixItAction : public ASTFrontendAction { -private: +protected: llvm::OwningPtr<FixItRewriter> Rewriter; llvm::OwningPtr<FixItPathRewriter> PathRewriter; -protected: - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile); @@ -133,6 +131,12 @@ public: virtual bool hasCodeCompletionSupport() const { return true; } }; +class BoostConAction : public SyntaxOnlyAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile); +}; + /** * \brief Frontend action adaptor that merges ASTs together. * diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 60512edd6c1f..c43e68000952 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -23,13 +23,15 @@ namespace frontend { ASTPrint, ///< Parse ASTs and print them. ASTPrintXML, ///< Parse ASTs and print them in XML. ASTView, ///< Parse ASTs and view them in Graphviz. + BoostCon, ///< BoostCon mode. DumpRawTokens, ///< Dump out raw tokens. DumpTokens, ///< Dump out preprocessed tokens. EmitAssembly, ///< Emit a .s file. EmitBC, ///< Emit a .bc file. EmitHTML, ///< Translate input source into HTML. EmitLLVM, ///< Emit a .ll file. - EmitLLVMOnly, ///< Generate LLVM IR, but do not + EmitLLVMOnly, ///< Generate LLVM IR, but do not emit anything. + EmitCodeGenOnly, ///< Generate machine code, but don't emit anything. EmitObj, ///< Emit a .o file. FixIt, ///< Parse and apply any fixits to the source. GeneratePCH, ///< Generate pre-compiled header. @@ -77,6 +79,8 @@ public: unsigned ShowHelp : 1; ///< Show the -help text. unsigned ShowMacrosInCodeCompletion : 1; ///< Show macros in code completion /// results. + unsigned ShowCodePatternsInCodeCompletion : 1; ///< Show code patterns in code + /// completion results. unsigned ShowStats : 1; ///< Show frontend performance /// metrics and statistics. unsigned ShowTimers : 1; ///< Show timers for individual @@ -123,6 +127,7 @@ public: RelocatablePCH = 0; ShowHelp = 0; ShowMacrosInCodeCompletion = 0; + ShowCodePatternsInCodeCompletion = 0; ShowStats = 0; ShowTimers = 0; ShowVersion = 0; diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 1640afb4122a..2493cfd47d1e 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -415,7 +415,9 @@ namespace clang { /// \brief An UnresolvedUsingType record. TYPE_UNRESOLVED_USING = 26, /// \brief An InjectedClassNameType record. - TYPE_INJECTED_CLASS_NAME = 27 + TYPE_INJECTED_CLASS_NAME = 27, + /// \brief An ObjCObjectType record. + TYPE_OBJC_OBJECT = 28 }; /// \brief The type IDs for special types constructed by semantic @@ -534,8 +536,46 @@ namespace clang { /// IDs. This data is used when performing qualified name lookup /// into a DeclContext via DeclContext::lookup. DECL_CONTEXT_VISIBLE, - /// \brief A NamespaceDecl record. - DECL_NAMESPACE + /// \brief A NamespaceDecl rcord. + DECL_NAMESPACE, + /// \brief A NamespaceAliasDecl record. + DECL_NAMESPACE_ALIAS, + /// \brief A UsingDecl record. + DECL_USING, + /// \brief A UsingShadowDecl record. + DECL_USING_SHADOW, + /// \brief A UsingDirecitveDecl record. + DECL_USING_DIRECTIVE, + /// \brief An UnresolvedUsingValueDecl record. + DECL_UNRESOLVED_USING_VALUE, + /// \brief An UnresolvedUsingTypenameDecl record. + DECL_UNRESOLVED_USING_TYPENAME, + /// \brief A LinkageSpecDecl record. + DECL_LINKAGE_SPEC, + /// \brief A CXXRecordDecl record. + DECL_CXX_RECORD, + /// \brief A CXXMethodDecl record. + DECL_CXX_METHOD, + /// \brief A CXXConstructorDecl record. + DECL_CXX_CONSTRUCTOR, + /// \brief A CXXDestructorDecl record. + DECL_CXX_DESTRUCTOR, + /// \brief A CXXConversionDecl record. + DECL_CXX_CONVERSION, + + // FIXME: Implement serialization for these decl types. This just + // allocates the order in which + DECL_FRIEND, + DECL_FRIEND_TEMPLATE, + DECL_TEMPLATE, + DECL_CLASS_TEMPLATE, + DECL_CLASS_TEMPLATE_SPECIALIZATION, + DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, + DECL_FUNCTION_TEMPLATE, + DECL_TEMPLATE_TYPE_PARM, + DECL_NON_TYPE_TEMPLATE_PARM, + DECL_TEMPLATE_TEMPLATE_PARM, + DECL_STATIC_ASSERT }; /// \brief Record codes for each kind of statement or expression. @@ -692,6 +732,8 @@ namespace clang { /// \brief A CXXOperatorCallExpr record. EXPR_CXX_OPERATOR_CALL, + /// \brief A CXXMemberCallExpr record. + EXPR_CXX_MEMBER_CALL, /// \brief A CXXConstructExpr record. EXPR_CXX_CONSTRUCT, // \brief A CXXStaticCastExpr record. @@ -706,8 +748,18 @@ namespace clang { EXPR_CXX_FUNCTIONAL_CAST, // \brief A CXXBoolLiteralExpr record. EXPR_CXX_BOOL_LITERAL, - // \brief A CXXNullPtrLiteralExpr record. - EXPR_CXX_NULL_PTR_LITERAL + EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr + EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). + EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). + EXPR_CXX_THIS, // CXXThisExpr + EXPR_CXX_THROW, // CXXThrowExpr + EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr + EXPR_CXX_BIND_TEMPORARY, // CXXBindTemporaryExpr + // + EXPR_CXX_ZERO_INIT_VALUE, // CXXZeroInitValueExpr + EXPR_CXX_NEW, // CXXNewExpr + + EXPR_CXX_EXPR_WITH_TEMPORARIES // CXXExprWithTemporaries }; /// \brief The kinds of designators that can occur in a diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index c2352301caa0..e144738236ea 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -52,6 +52,9 @@ class ASTContext; class Attr; class Decl; class DeclContext; +class NestedNameSpecifier; +class CXXBaseSpecifier; +class CXXBaseOrMemberInitializer; class GotoStmt; class LabelStmt; class MacroDefinition; @@ -649,8 +652,8 @@ public: /// declarations with this name are visible from translation unit scope, their /// declarations will be deserialized and introduced into the declaration /// chain of the identifier. - virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd); - IdentifierInfo* get(llvm::StringRef Name) { + virtual IdentifierInfo *get(const char *NameStart, const char *NameEnd); + IdentifierInfo *get(llvm::StringRef Name) { return get(Name.begin(), Name.end()); } @@ -694,8 +697,21 @@ public: Selector GetSelector(const RecordData &Record, unsigned &Idx) { return DecodeSelector(Record[Idx++]); } + + /// \brief Read a declaration name. DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx); + NestedNameSpecifier *ReadNestedNameSpecifier(const RecordData &Record, + unsigned &Idx); + + /// \brief Read a source location. + SourceLocation ReadSourceLocation(const RecordData &Record, unsigned& Idx) { + return SourceLocation::getFromRawEncoding(Record[Idx++]); + } + + /// \brief Read a source range. + SourceRange ReadSourceRange(const RecordData &Record, unsigned& Idx); + /// \brief Read an integral value llvm::APInt ReadAPInt(const RecordData &Record, unsigned &Idx); @@ -708,6 +724,8 @@ public: // \brief Read a string std::string ReadString(const RecordData &Record, unsigned &Idx); + CXXTemporary *ReadCXXTemporary(const RecordData &Record, unsigned &Idx); + /// \brief Reads attributes from the current stream position. Attr *ReadAttributes(); diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index e006de524ca3..85f53b9e0302 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -32,6 +32,9 @@ namespace llvm { namespace clang { class ASTContext; +class NestedNameSpecifier; +class CXXBaseSpecifier; +class CXXBaseOrMemberInitializer; class LabelStmt; class MacroDefinition; class MemorizeStatCalls; @@ -251,6 +254,9 @@ public: /// \brief Emit a source location. void AddSourceLocation(SourceLocation Loc, RecordData &Record); + /// \brief Emit a source range. + void AddSourceRange(SourceRange Range, RecordData &Record); + /// \brief Emit an integral value. void AddAPInt(const llvm::APInt &Value, RecordData &Record); @@ -260,12 +266,15 @@ public: /// \brief Emit a floating-point value. void AddAPFloat(const llvm::APFloat &Value, RecordData &Record); - /// \brief Emit a reference to an identifier + /// \brief Emit a reference to an identifier. void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record); - /// \brief Emit a Selector (which is a smart pointer reference) - void AddSelectorRef(const Selector, RecordData &Record); + /// \brief Emit a Selector (which is a smart pointer reference). + void AddSelectorRef(Selector, RecordData &Record); + /// \brief Emit a CXXTemporary. + void AddCXXTemporary(const CXXTemporary *Temp, RecordData &Record); + /// \brief Get the unique number used to refer to the given /// identifier. pch::IdentID getIdentifierRef(const IdentifierInfo *II); @@ -304,6 +313,9 @@ public: /// \brief Emit a declaration name. void AddDeclarationName(DeclarationName Name, RecordData &Record); + /// \brief Emit a nested name specifier. + void AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordData &Record); + /// \brief Add a string to the given record. void AddString(const std::string &Str, RecordData &Record); diff --git a/include/clang/Frontend/TypeXML.def b/include/clang/Frontend/TypeXML.def index 3add99a941c4..069d718d9def 100644 --- a/include/clang/Frontend/TypeXML.def +++ b/include/clang/Frontend/TypeXML.def @@ -61,6 +61,10 @@ # define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context") #endif +NODE_XML(Type, "FIXME_Type") + ID_ATTRIBUTE_XML + ATTRIBUTE_XML(getTypeClassName(), "unhandled_type_name") +END_NODE_XML NODE_XML(QualType, "CvQualifiedType") ID_ATTRIBUTE_XML @@ -207,9 +211,9 @@ NODE_XML(RecordType, "Record") ID_ATTRIBUTE_XML ATTRIBUTE_XML(getDecl()->getNameAsString(), "name") // string ATTRIBUTE_ENUM_XML(getDecl()->getTagKind(), "kind") - ENUM_XML(TagDecl::TK_struct, "struct") - ENUM_XML(TagDecl::TK_union, "union") - ENUM_XML(TagDecl::TK_class, "class") + ENUM_XML(TTK_Struct, "struct") + ENUM_XML(TTK_Union, "union") + ENUM_XML(TTK_Class, "class") END_ENUM_XML CONTEXT_ATTRIBUTE_XML(getDecl()->getDeclContext()) END_NODE_XML @@ -228,11 +232,23 @@ NODE_XML(TemplateSpecializationType, "TemplateSpecializationType") ID_ATTRIBUTE_XML END_NODE_XML -NODE_XML(QualifiedNameType, "QualifiedNameType") +NODE_XML(ElaboratedType, "ElaboratedType") ID_ATTRIBUTE_XML + ATTRIBUTE_ENUM_XML(getKeyword(), "keyword") + ENUM_XML(ETK_None, "none") + ENUM_XML(ETK_Typename, "typename") + ENUM_XML(ETK_Struct, "struct") + ENUM_XML(ETK_Union, "union") + ENUM_XML(ETK_Class, "class") + ENUM_XML(ETK_Enum, "enum") + END_ENUM_XML TYPE_ATTRIBUTE_XML(getNamedType()) END_NODE_XML +NODE_XML(InjectedClassNameType, "InjectedClassNameType") + ID_ATTRIBUTE_XML +END_NODE_XML + NODE_XML(DependentNameType, "DependentNameType") ID_ATTRIBUTE_XML END_NODE_XML @@ -245,6 +261,29 @@ NODE_XML(ObjCObjectPointerType, "ObjCObjectPointerType") ID_ATTRIBUTE_XML END_NODE_XML +NODE_XML(SubstTemplateTypeParmType, "SubstTemplateTypeParm") + ID_ATTRIBUTE_XML +END_NODE_XML + +NODE_XML(DependentSizedExtVectorType, "DependentSizedExtVector") + ID_ATTRIBUTE_XML +END_NODE_XML + +NODE_XML(UnresolvedUsingType, "UnresolvedUsing") + ID_ATTRIBUTE_XML +END_NODE_XML + +NODE_XML(DependentTypeOfExprType, "DependentTypeOfExpr") + ID_ATTRIBUTE_XML +END_NODE_XML + +NODE_XML(DecltypeType, "Decltype") + ID_ATTRIBUTE_XML +END_NODE_XML + +NODE_XML(DependentDecltypeType, "DependentDecltype") + ID_ATTRIBUTE_XML +END_NODE_XML //===----------------------------------------------------------------------===// #undef NODE_XML diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h index 2334d728f6e3..ba46fb18a68a 100644 --- a/include/clang/Lex/LiteralSupport.h +++ b/include/clang/Lex/LiteralSupport.h @@ -147,7 +147,7 @@ class StringLiteralParser { char *ResultPtr; // cursor public: StringLiteralParser(const Token *StringToks, unsigned NumStringToks, - Preprocessor &PP); + Preprocessor &PP, bool Complain = true); bool hadError; bool AnyWide; bool Pascal; @@ -164,7 +164,7 @@ public: /// specified byte of the string data represented by Token. This handles /// advancing over escape sequences in the string. static unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo, - Preprocessor &PP); + Preprocessor &PP, bool Complain = true); }; } // end namespace clang diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 20d9fc50e49f..f01b3afc45f5 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -290,8 +290,8 @@ public: /// expansions going on at the time. PreprocessorLexer *getCurrentLexer() const { return CurPPLexer; } - /// getCurrentFileLexer - Return the current file lexer being lexed from. Note - /// that this ignores any potentially active macro expansions and _Pragma + /// getCurrentFileLexer - Return the current file lexer being lexed from. + /// Note that this ignores any potentially active macro expansions and _Pragma /// expansions going on at the time. PreprocessorLexer *getCurrentFileLexer() const; @@ -753,9 +753,9 @@ public: /// #include FOO /// because in this case, "<a/b.h>" is returned as 7 tokens, not one. /// - /// 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. + /// 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::SmallString<128> &FilenameBuffer); private: @@ -900,8 +900,6 @@ private: // Macro handling. void HandleDefineDirective(Token &Tok); void HandleUndefDirective(Token &Tok); - // HandleAssertDirective(Token &Tok); - // HandleUnassertDirective(Token &Tok); // Conditional Inclusion. void HandleIfdefDirective(Token &Tok, bool isIfndef, diff --git a/include/clang/Makefile b/include/clang/Makefile index d76e0a9c63ba..6abe375d5e97 100644 --- a/include/clang/Makefile +++ b/include/clang/Makefile @@ -1,5 +1,5 @@ LEVEL = ../../../.. -DIRS := Basic Driver +DIRS := AST Basic Driver include $(LEVEL)/Makefile.common @@ -10,7 +10,7 @@ install-local:: cd $(PROJ_SRC_ROOT)/tools/clang/include && \ for hdr in `find clang -type f '!' '(' -name '*~' \ -o -name '.#*' -o -name '*.in' -o -name '*.txt' \ - -o -name 'Makefile' -o -name '*.td' ')' -print \ + -o -name 'Makefile' -o -name '*.td' -o -name '*.orig' ')' -print \ | grep -v CVS | grep -v .svn | grep -v .dir` ; do \ instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \ if test \! -d "$$instdir" ; then \ diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 3d68d80ef9f0..e21da81a8aa8 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -105,12 +105,19 @@ public: class FullExprArg { public: + FullExprArg(ActionBase &actions) : Expr(actions) { } + // FIXME: The const_cast here is ugly. RValue references would make this // much nicer (or we could duplicate a bunch of the move semantics // emulation code from Ownership.h). FullExprArg(const FullExprArg& Other) : Expr(move(const_cast<FullExprArg&>(Other).Expr)) {} + FullExprArg &operator=(const FullExprArg& Other) { + Expr.operator=(move(const_cast<FullExprArg&>(Other).Expr)); + return *this; + } + OwningExprResult release() { return move(Expr); } @@ -279,13 +286,18 @@ public: /// \param Template if the name does refer to a template, the declaration /// of the template that the name refers to. /// + /// \param MemberOfUnknownSpecialization Will be set true if the resulting + /// member would be a member of an unknown specialization, in which case this + /// lookup cannot possibly pass at this time. + /// /// \returns the kind of template that this name refers to. virtual TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, - TemplateTy &Template) = 0; + TemplateTy &Template, + bool &MemberOfUnknownSpecialization) = 0; /// \brief Action called as part of error recovery when the parser has /// determined that the given name must refer to a template, but @@ -566,7 +578,9 @@ public: /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, + AccessSpecifier Access, + DeclSpec &DS) { return DeclPtrTy(); } @@ -826,21 +840,19 @@ public: /// \brief Parsed the start of a "switch" statement. /// + /// \param SwitchLoc The location of the "switch" keyword. + /// /// \param Cond if the "switch" condition was parsed as an expression, /// the expression itself. /// /// \param CondVar if the "switch" condition was parsed as a condition /// variable, the condition variable itself. - virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + ExprArg Cond, DeclPtrTy CondVar) { return StmtEmpty(); } - /// ActOnSwitchBodyError - This is called if there is an error parsing the - /// body of the switch stmt instead of ActOnFinishSwitchStmt. - virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, - StmtArg Body) {} - virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body) { return StmtEmpty(); @@ -1609,6 +1621,22 @@ public: return DeclResult(); } + /// \brief Parsed an expression that will be handled as the condition in + /// an if/while/for statement. + /// + /// This routine handles the conversion of the expression to 'bool'. + /// + /// \param S The scope in which the expression occurs. + /// + /// \param Loc The location of the construct that requires the conversion to + /// a boolean value. + /// + /// \param SubExpr The expression that is being converted to bool. + virtual OwningExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc, + ExprArg SubExpr) { + return move(SubExpr); + } + /// ActOnCXXNew - Parsed a C++ 'new' expression. UseGlobal is true if the /// new was qualified (::new). In a full new like /// @code new (p1, p2) type(c1, c2) @endcode @@ -2303,6 +2331,7 @@ public: } // ActOnPropertyImplDecl - called for every property implementation virtual DeclPtrTy ActOnPropertyImplDecl( + Scope *S, SourceLocation AtLoc, // location of the @synthesize/@dynamic SourceLocation PropertyNameLoc, // location for the property name bool ImplKind, // true for @synthesize, false for @@ -2346,7 +2375,7 @@ public: // protocols, categories), the parser passes all methods/properties. // For class implementations, these values default to 0. For implementations, // methods are processed incrementally (by ActOnMethodDeclaration above). - virtual void ActOnAtEnd(SourceRange AtEnd, + virtual void ActOnAtEnd(Scope *S, SourceRange AtEnd, DeclPtrTy classDecl, DeclPtrTy *allMethods = 0, unsigned allNum = 0, @@ -2535,6 +2564,21 @@ public: //===---------------------------- Pragmas -------------------------------===// + enum PragmaOptionsAlignKind { + POAK_Natural, // #pragma options align=natural + POAK_Power, // #pragma options align=power + POAK_Mac68k, // #pragma options align=mac68k + POAK_Reset // #pragma options align=reset + }; + + /// ActOnPragmaOptionsAlign - Called on well formed #pragma options + /// align={...}. + virtual void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, + SourceLocation PragmaLoc, + SourceLocation KindLoc) { + return; + } + enum PragmaPackKind { PPK_Default, // #pragma pack([n]) PPK_Show, // #pragma pack(show), only supported by MSVC. @@ -2620,9 +2664,13 @@ public: /// \brief Code completion occurs at the beginning of the /// initialization statement (or expression) in a for loop. CCC_ForInit, - /// \brief Code completion ocurs within the condition of an if, + /// \brief Code completion occurs within the condition of an if, /// while, switch, or for statement. - CCC_Condition + CCC_Condition, + /// \brief Code completion occurs within the body of a function on a + /// recovery path, where we do not have a specific handle on our position + /// in the grammar. + CCC_RecoveryInFunction }; /// \brief Code completion for an ordinary name that occurs within the given @@ -3003,7 +3051,9 @@ public: UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, - TemplateTy &Template); + TemplateTy &Template, + bool &MemberOfUnknownSpecialization); + /// ActOnDeclarator - If this is a typedef declarator, we modify the /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 12512f33c761..1e6d3ab9760d 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -55,6 +55,7 @@ public: enum Kind { // Please keep this list alphabetized. AT_IBAction, // Clang-specific. AT_IBOutlet, // Clang-specific. + AT_IBOutletCollection, // Clang-specific. AT_address_space, AT_alias, AT_aligned, @@ -102,6 +103,7 @@ public: AT_section, AT_sentinel, AT_stdcall, + AT_thiscall, AT_transparent_union, AT_unavailable, AT_unused, diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h index 5eb9635f06a1..e9a20b7872b5 100644 --- a/include/clang/Parse/Ownership.h +++ b/include/clang/Parse/Ownership.h @@ -166,7 +166,7 @@ namespace llvm { // conversions. // Flip this switch to measure performance impact of the smart pointers. -//#define DISABLE_SMART_POINTERS +// #define DISABLE_SMART_POINTERS namespace llvm { template<> @@ -403,8 +403,10 @@ namespace clang { friend class moving::ASTResultMover<Destroyer>; +#if !(defined(_MSC_VER) && _MSC_VER >= 1600) ASTOwningResult(ASTOwningResult&); // DO NOT IMPLEMENT ASTOwningResult& operator =(ASTOwningResult&); // DO NOT IMPLEMENT +#endif void destroy() { if (Ptr) { @@ -444,6 +446,19 @@ namespace clang { return *this; } +#if defined(_MSC_VER) && _MSC_VER >= 1600 + // Emulated move semantics don't work with msvc. + ASTOwningResult(ASTOwningResult &&mover) + : ActionInv(mover.ActionInv), + Ptr(mover.Ptr) { + mover.Ptr = 0; + } + ASTOwningResult &operator=(ASTOwningResult &&mover) { + *this = moving::ASTResultMover<Destroyer>(mover); + return *this; + } +#endif + /// Assignment from a raw pointer. Takes ownership - beware! ASTOwningResult &operator=(void *raw) { destroy(); diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 42a41d6d3028..8081c2492b2f 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -110,6 +110,7 @@ class Parser { IdentifierInfo *Ident_vector; IdentifierInfo *Ident_pixel; + llvm::OwningPtr<PragmaHandler> OptionsHandler; llvm::OwningPtr<PragmaHandler> PackHandler; llvm::OwningPtr<PragmaHandler> UnusedHandler; llvm::OwningPtr<PragmaHandler> WeakHandler; @@ -234,6 +235,11 @@ private: assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() && !isTokenBrace() && "Should consume special tokens with Consume*Token"); + if (Tok.is(tok::code_completion)) { + CodeCompletionRecovery(); + return ConsumeCodeCompletionToken(); + } + PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; @@ -308,6 +314,22 @@ private: return PrevTokLocation; } + /// \brief Consume the current code-completion token. + /// + /// This routine should be called to consume the code-completion token once + /// a code-completion action has already been invoked. + SourceLocation ConsumeCodeCompletionToken() { + assert(Tok.is(tok::code_completion)); + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + ///\ brief When we are consuming a code-completion token within having + /// matched specific position in the grammar, provide code-completion results + /// based on context. + void CodeCompletionRecovery(); + /// GetLookAheadToken - This peeks ahead N tokens and returns that token /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) /// returns the token after Tok, etc. @@ -1004,7 +1026,8 @@ private: //===--------------------------------------------------------------------===// // C++ if/switch/while condition expression. - bool ParseCXXCondition(OwningExprResult &ExprResult, DeclPtrTy &DeclResult); + bool ParseCXXCondition(OwningExprResult &ExprResult, DeclPtrTy &DeclResult, + SourceLocation Loc, bool ConvertToBoolean); //===--------------------------------------------------------------------===// // C++ types @@ -1060,7 +1083,9 @@ private: bool isStmtExpr = false); OwningStmtResult ParseCompoundStatementBody(bool isStmtExpr = false); bool ParseParenExprOrCondition(OwningExprResult &ExprResult, - DeclPtrTy &DeclResult); + DeclPtrTy &DeclResult, + SourceLocation Loc, + bool ConvertToBoolean); OwningStmtResult ParseIfStatement(AttributeList *Attr); OwningStmtResult ParseSwitchStatement(AttributeList *Attr); OwningStmtResult ParseWhileStatement(AttributeList *Attr); @@ -1348,6 +1373,8 @@ private: AttributeList *AttrList = 0, bool RequiresArg = false); void ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, + IdentifierInfo *FirstIdent, + SourceLocation FirstIdentLoc, Declarator &D); void ParseBracketDeclarator(Declarator &D); @@ -1403,7 +1430,8 @@ private: bool EnteringContext, TypeTy *ObjectType, UnqualifiedId &Id, - bool AssumeTemplateId = false); + bool AssumeTemplateId, + SourceLocation TemplateKWLoc); bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, TypeTy *ObjectType, UnqualifiedId &Result); @@ -1457,6 +1485,7 @@ private: SourceLocation TemplateKWLoc = SourceLocation(), bool AllowTypeAnnotation = true); void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0); + bool IsTemplateArgumentList(unsigned Skip = 0); bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs); ParsedTemplateArgument ParseTemplateTemplateArgument(); ParsedTemplateArgument ParseTemplateArgument(); diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h index d7a0e3583ca5..023f40d3957c 100644 --- a/include/clang/Parse/Scope.h +++ b/include/clang/Parse/Scope.h @@ -74,7 +74,7 @@ public: /// It always has FnScope and DeclScope set as well. ObjCMethodScope = 0x400, - /// ElseScope - This scoep corresponds to an 'else' scope of an if/then/else + /// ElseScope - This scope corresponds to an 'else' scope of an if/then/else /// statement. ElseScope = 0x800 }; diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index 348917a7d034..1f1c0cc11325 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -24,6 +24,41 @@ class raw_ostream; namespace clang { +/// \brief Default priority values for code-completion results based +/// on their kind. +enum { + /// \brief Priority for a declaration that is in the local scope. + CCP_LocalDeclaration = 8, + /// \brief Priority for a member declaration found from the current + /// method or member function. + CCP_MemberDeclaration = 20, + /// \brief Priority for a language keyword (that isn't any of the other + /// categories). + CCP_Keyword = 30, + /// \brief Priority for a code pattern. + CCP_CodePattern = 30, + /// \brief Priority for a type. + CCP_Type = 40, + /// \brief Priority for a non-type declaration. + CCP_Declaration = 50, + /// \brief Priority for a constant value (e.g., enumerator). + CCP_Constant = 60, + /// \brief Priority for a preprocessor macro. + CCP_Macro = 70, + /// \brief Priority for a nested-name-specifier. + CCP_NestedNameSpecifier = 75, + /// \brief Priority for a result that isn't likely to be what the user wants, + /// but is included for completeness. + CCP_Unlikely = 80 +}; + +/// \brief Priority value deltas that are applied to code-completion results +/// based on the context of the result. +enum { + /// \brief The result is in a base class. + CCD_InBaseClass = 2 +}; + class FunctionDecl; class FunctionType; class FunctionTemplateDecl; @@ -156,13 +191,14 @@ private: public: CodeCompletionString() { } - ~CodeCompletionString(); + ~CodeCompletionString() { clear(); } typedef llvm::SmallVector<Chunk, 4>::const_iterator iterator; iterator begin() const { return Chunks.begin(); } iterator end() const { return Chunks.end(); } bool empty() const { return Chunks.empty(); } unsigned size() const { return Chunks.size(); } + void clear(); Chunk &operator[](unsigned I) { assert(I < size() && "Chunk index out-of-range"); @@ -232,8 +268,9 @@ public: void Serialize(llvm::raw_ostream &OS) const; /// \brief Deserialize a code-completion string from the given string. - static CodeCompletionString *Deserialize(const char *&Str, - const char *StrEnd); + /// + /// \returns true if successful, false otherwise. + bool Deserialize(const char *&Str, const char *StrEnd); }; llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, @@ -246,6 +283,10 @@ protected: /// \brief Whether to include macros in the code-completion results. bool IncludeMacros; + /// \brief Whether to include code patterns (such as for loops) within + /// the completion results. + bool IncludeCodePatterns; + /// \brief Whether the output format for the code-completion consumer is /// binary. bool OutputIsBinary; @@ -280,8 +321,11 @@ public: /// \brief When Kind == RK_Macro, the identifier that refers to a macro. IdentifierInfo *Macro; }; - - /// \brief Specifiers which parameter (of a function, Objective-C method, + + /// \brief The priority of this particular code-completion result. + unsigned Priority; + + /// \brief Specifies which parameter (of a function, Objective-C method, /// macro, etc.) we should start with when formatting the result. unsigned StartParameter; @@ -309,29 +353,30 @@ public: NestedNameSpecifier *Qualifier = 0, bool QualifierIsInformative = false) : Kind(RK_Declaration), Declaration(Declaration), - StartParameter(0), Hidden(false), - QualifierIsInformative(QualifierIsInformative), + Priority(getPriorityFromDecl(Declaration)), StartParameter(0), + Hidden(false), QualifierIsInformative(QualifierIsInformative), StartsNestedNameSpecifier(false), AllParametersAreInformative(false), - Qualifier(Qualifier) { } + Qualifier(Qualifier) { + } /// \brief Build a result that refers to a keyword or symbol. - Result(const char *Keyword) - : Kind(RK_Keyword), Keyword(Keyword), StartParameter(0), - Hidden(false), QualifierIsInformative(0), + Result(const char *Keyword, unsigned Priority = CCP_Keyword) + : Kind(RK_Keyword), Keyword(Keyword), Priority(Priority), + StartParameter(0), Hidden(false), QualifierIsInformative(0), StartsNestedNameSpecifier(false), AllParametersAreInformative(false), Qualifier(0) { } /// \brief Build a result that refers to a macro. - Result(IdentifierInfo *Macro) - : Kind(RK_Macro), Macro(Macro), StartParameter(0), + Result(IdentifierInfo *Macro, unsigned Priority = CCP_Macro) + : Kind(RK_Macro), Macro(Macro), Priority(Priority), StartParameter(0), Hidden(false), QualifierIsInformative(0), StartsNestedNameSpecifier(false), AllParametersAreInformative(false), Qualifier(0) { } /// \brief Build a result that refers to a pattern. - Result(CodeCompletionString *Pattern) - : Kind(RK_Pattern), Pattern(Pattern), StartParameter(0), - Hidden(false), QualifierIsInformative(0), + Result(CodeCompletionString *Pattern, unsigned Priority = CCP_CodePattern) + : Kind(RK_Pattern), Pattern(Pattern), Priority(Priority), + StartParameter(0), Hidden(false), QualifierIsInformative(0), StartsNestedNameSpecifier(false), AllParametersAreInformative(false), Qualifier(0) { } @@ -352,6 +397,9 @@ public: CodeCompletionString *CreateCodeCompletionString(Sema &S); void Destroy(); + + /// brief Determine a base priority for the given declaration. + static unsigned getPriorityFromDecl(NamedDecl *ND); }; class OverloadCandidate { @@ -420,12 +468,17 @@ public: CodeCompleteConsumer() : IncludeMacros(false), OutputIsBinary(false) { } - CodeCompleteConsumer(bool IncludeMacros, bool OutputIsBinary) - : IncludeMacros(IncludeMacros), OutputIsBinary(OutputIsBinary) { } + CodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, + bool OutputIsBinary) + : IncludeMacros(IncludeMacros), IncludeCodePatterns(IncludeCodePatterns), + OutputIsBinary(OutputIsBinary) { } /// \brief Whether the code-completion consumer wants to see macros. bool includeMacros() const { return IncludeMacros; } + /// \brief Whether the code-completion consumer wants to see code patterns. + bool includeCodePatterns() const { return IncludeCodePatterns; } + /// \brief Determine whether the output of this consumer is binary. bool isOutputBinary() const { return OutputIsBinary; } @@ -461,9 +514,9 @@ class PrintingCodeCompleteConsumer : public CodeCompleteConsumer { public: /// \brief Create a new printing code-completion consumer that prints its /// results to the given raw output stream. - PrintingCodeCompleteConsumer(bool IncludeMacros, + PrintingCodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros, false), OS(OS) { } + : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, false), OS(OS) {} /// \brief Prints the finalized code-completion results. virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, @@ -484,8 +537,9 @@ public: /// \brief Create a new CIndex code-completion consumer that prints its /// results to the given raw output stream in a format readable to the CIndex /// library. - CIndexCodeCompleteConsumer(bool IncludeMacros, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros, true), OS(OS) { } + CIndexCodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, + llvm::raw_ostream &OS) + : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, true), OS(OS) {} /// \brief Prints the finalized code-completion results. virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index eea727deb44d..851f8d1c68bf 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" @@ -27,7 +28,6 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" -#include "RecordLayoutBuilder.h" using namespace clang; @@ -46,7 +46,9 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), - BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts), + BuiltinInfo(builtins), + DeclarationNames(*this), + ExternalSource(0), PrintingPolicy(LOpts), LastSDM(0, 0) { ObjCIdRedefinitionType = QualType(); ObjCClassRedefinitionType = QualType(); @@ -61,6 +63,12 @@ ASTContext::~ASTContext() { // FIXME: Is this the ideal solution? ReleaseDeclContextMaps(); + if (!FreeMemory) { + // Call all of the deallocation functions. + for (unsigned I = 0, N = Deallocations.size(); I != N; ++I) + Deallocations[I].first(Deallocations[I].second); + } + // Release all of the memory associated with overridden C++ methods. for (llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::iterator OM = OverriddenMethods.begin(), OMEnd = OverriddenMethods.end(); @@ -111,6 +119,10 @@ ASTContext::~ASTContext() { TUDecl->Destroy(*this); } +void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { + Deallocations.push_back(std::make_pair(Callback, Data)); +} + void ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) { ExternalSource.reset(Source.take()); @@ -419,6 +431,18 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) { return CharUnits::fromQuantity(Align / Target.getCharWidth()); } +std::pair<CharUnits, CharUnits> +ASTContext::getTypeInfoInChars(const Type *T) { + std::pair<uint64_t, unsigned> Info = getTypeInfo(T); + return std::make_pair(CharUnits::fromQuantity(Info.first / getCharWidth()), + CharUnits::fromQuantity(Info.second / getCharWidth())); +} + +std::pair<CharUnits, CharUnits> +ASTContext::getTypeInfoInChars(QualType T) { + return getTypeInfoInChars(T.getTypePtr()); +} + /// getTypeSize - Return the size of the specified type, in bits. This method /// does not work on incomplete types. /// @@ -593,6 +617,8 @@ ASTContext::getTypeInfo(const Type *T) { Align = EltInfo.second; break; } + case Type::ObjCObject: + return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr()); case Type::ObjCInterface: { const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T); const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); @@ -624,10 +650,6 @@ ASTContext::getTypeInfo(const Type *T) { return getTypeInfo(cast<SubstTemplateTypeParmType>(T)-> getReplacementType().getTypePtr()); - case Type::Elaborated: - return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType() - .getTypePtr()); - case Type::Typedef: { const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl(); if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) { @@ -650,8 +672,8 @@ ASTContext::getTypeInfo(const Type *T) { return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType() .getTypePtr()); - case Type::QualifiedName: - return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr()); + case Type::Elaborated: + return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr()); case Type::TemplateSpecialization: assert(getCanonicalType(T) != T && @@ -875,40 +897,6 @@ TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T, return DI; } -/// getInterfaceLayoutImpl - Get or compute information about the -/// layout of the given interface. -/// -/// \param Impl - If given, also include the layout of the interface's -/// implementation. This may differ by including synthesized ivars. -const ASTRecordLayout & -ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, - const ObjCImplementationDecl *Impl) { - assert(!D->isForwardDecl() && "Invalid interface decl!"); - - // Look up this layout, if already laid out, return what we have. - ObjCContainerDecl *Key = - Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D; - if (const ASTRecordLayout *Entry = ObjCLayouts[Key]) - return *Entry; - - // Add in synthesized ivar count if laying out an implementation. - if (Impl) { - unsigned SynthCount = CountNonClassIvars(D); - // If there aren't any sythesized ivars then reuse the interface - // entry. Note we can't cache this because we simply free all - // entries later; however we shouldn't look up implementations - // frequently. - if (SynthCount == 0) - return getObjCLayout(D, 0); - } - - const ASTRecordLayout *NewEntry = - ASTRecordLayoutBuilder::ComputeLayout(*this, D, Impl); - ObjCLayouts[Key] = NewEntry; - - return *NewEntry; -} - const ASTRecordLayout & ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) { return getObjCLayout(D, 0); @@ -919,45 +907,6 @@ ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) { return getObjCLayout(D->getClassInterface(), D); } -/// getASTRecordLayout - Get or compute information about the layout of the -/// specified record (struct/union/class), which indicates its size and field -/// position information. -const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { - D = D->getDefinition(); - assert(D && "Cannot get layout of forward declarations!"); - - // Look up this layout, if already laid out, return what we have. - // Note that we can't save a reference to the entry because this function - // is recursive. - const ASTRecordLayout *Entry = ASTRecordLayouts[D]; - if (Entry) return *Entry; - - const ASTRecordLayout *NewEntry = - ASTRecordLayoutBuilder::ComputeLayout(*this, D); - ASTRecordLayouts[D] = NewEntry; - - if (getLangOptions().DumpRecordLayouts) { - llvm::errs() << "\n*** Dumping AST Record Layout\n"; - DumpRecordLayout(D, llvm::errs()); - } - - return *NewEntry; -} - -const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { - RD = cast<CXXRecordDecl>(RD->getDefinition()); - assert(RD && "Cannot get key function for forward declarations!"); - - const CXXMethodDecl *&Entry = KeyFunctions[RD]; - if (!Entry) - Entry = ASTRecordLayoutBuilder::ComputeKeyFunction(RD); - else - assert(Entry == ASTRecordLayoutBuilder::ComputeKeyFunction(RD) && - "Key function changed!"); - - return Entry; -} - //===----------------------------------------------------------------------===// // Type creation/memoization methods //===----------------------------------------------------------------------===// @@ -1343,9 +1292,17 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, SourceRange Brackets) { // Since we don't unique expressions, it isn't possible to unique VLA's // that have an expression provided for their size. - + QualType CanonType; + + if (!EltTy.isCanonical()) { + if (NumElts) + NumElts->Retain(); + CanonType = getVariableArrayType(getCanonicalType(EltTy), NumElts, ASM, + EltTypeQuals, Brackets); + } + VariableArrayType *New = new(*this, TypeAlignment) - VariableArrayType(EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets); + VariableArrayType(EltTy, CanonType, NumElts, ASM, EltTypeQuals, Brackets); VariableArrayTypes.push_back(New); Types.push_back(New); @@ -1694,10 +1651,6 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) { if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl)) return getTypedefType(Typedef); - if (const ObjCInterfaceDecl *ObjCInterface - = dyn_cast<ObjCInterfaceDecl>(Decl)) - return getObjCInterfaceType(ObjCInterface); - assert(!isa<TemplateTypeParmDecl>(Decl) && "Template type parameter types are always available."); @@ -1888,29 +1841,28 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, } QualType -ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS, - QualType NamedType) { +ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + QualType NamedType) { llvm::FoldingSetNodeID ID; - QualifiedNameType::Profile(ID, NNS, NamedType); + ElaboratedType::Profile(ID, Keyword, NNS, NamedType); void *InsertPos = 0; - QualifiedNameType *T - = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos); + ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); QualType Canon = NamedType; if (!Canon.isCanonical()) { Canon = getCanonicalType(NamedType); - QualifiedNameType *CheckT - = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(!CheckT && "Qualified name canonical type broken"); + ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Elaborated canonical type broken"); (void)CheckT; } - T = new (*this) QualifiedNameType(NNS, NamedType, Canon); + T = new (*this) ElaboratedType(Keyword, NNS, NamedType, Canon); Types.push_back(T); - QualifiedNameTypes.InsertNode(T, InsertPos); + ElaboratedTypes.InsertNode(T, InsertPos); return QualType(T, 0); } @@ -1987,30 +1939,6 @@ ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, return QualType(T, 0); } -QualType -ASTContext::getElaboratedType(QualType UnderlyingType, - ElaboratedType::TagKind Tag) { - llvm::FoldingSetNodeID ID; - ElaboratedType::Profile(ID, UnderlyingType, Tag); - - void *InsertPos = 0; - ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); - if (T) - return QualType(T, 0); - - QualType Canon = UnderlyingType; - if (!Canon.isCanonical()) { - Canon = getCanonicalType(Canon); - ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(!CheckT && "Elaborated canonical type is broken"); (void)CheckT; - } - - T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon); - Types.push_back(T); - ElaboratedTypes.InsertNode(T, InsertPos); - return QualType(T, 0); -} - /// CmpProtocolNames - Comparison predicate for sorting protocols /// alphabetically. static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, @@ -2018,7 +1946,7 @@ static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, return LHS->getDeclName() < RHS->getDeclName(); } -static bool areSortedAndUniqued(ObjCProtocolDecl **Protocols, +static bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) { if (NumProtocols == 0) return true; @@ -2040,96 +1968,98 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols, NumProtocols = ProtocolsEnd-Protocols; } -/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for -/// the given interface decl and the conforming protocol list. -QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, - ObjCProtocolDecl **Protocols, - unsigned NumProtocols, - unsigned Quals) { - llvm::FoldingSetNodeID ID; - ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols); - Qualifiers Qs = Qualifiers::fromCVRMask(Quals); +QualType ASTContext::getObjCObjectType(QualType BaseType, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) { + // If the base type is an interface and there aren't any protocols + // to add, then the interface type will do just fine. + if (!NumProtocols && isa<ObjCInterfaceType>(BaseType)) + return BaseType; + // Look in the folding set for an existing type. + llvm::FoldingSetNodeID ID; + ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols); void *InsertPos = 0; - if (ObjCObjectPointerType *QT = - ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) - return getQualifiedType(QualType(QT, 0), Qs); + if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); - // Sort the protocol list alphabetically to canonicalize it. + // Build the canonical type, which has the canonical base type and + // a sorted-and-uniqued list of protocols. QualType Canonical; - if (!InterfaceT.isCanonical() || - !areSortedAndUniqued(Protocols, NumProtocols)) { - if (!areSortedAndUniqued(Protocols, NumProtocols)) { + bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols); + if (!ProtocolsSorted || !BaseType.isCanonical()) { + if (!ProtocolsSorted) { llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, Protocols + NumProtocols); unsigned UniqueCount = NumProtocols; SortAndUniqueProtocols(&Sorted[0], UniqueCount); - - Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT), - &Sorted[0], UniqueCount); + Canonical = getObjCObjectType(getCanonicalType(BaseType), + &Sorted[0], UniqueCount); } else { - Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT), - Protocols, NumProtocols); + Canonical = getObjCObjectType(getCanonicalType(BaseType), + Protocols, NumProtocols); } // Regenerate InsertPos. - ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos); + ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos); } - // No match. - unsigned Size = sizeof(ObjCObjectPointerType) - + NumProtocols * sizeof(ObjCProtocolDecl *); + unsigned Size = sizeof(ObjCObjectTypeImpl); + Size += NumProtocols * sizeof(ObjCProtocolDecl *); void *Mem = Allocate(Size, TypeAlignment); - ObjCObjectPointerType *QType = new (Mem) ObjCObjectPointerType(Canonical, - InterfaceT, - Protocols, - NumProtocols); + ObjCObjectTypeImpl *T = + new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols); - Types.push_back(QType); - ObjCObjectPointerTypes.InsertNode(QType, InsertPos); - return getQualifiedType(QualType(QType, 0), Qs); + Types.push_back(T); + ObjCObjectTypes.InsertNode(T, InsertPos); + return QualType(T, 0); } -/// getObjCInterfaceType - Return the unique reference to the type for the -/// specified ObjC interface decl. The list of protocols is optional. -QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **Protocols, unsigned NumProtocols) { +/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for +/// the given object type. +QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) { llvm::FoldingSetNodeID ID; - ObjCInterfaceType::Profile(ID, Decl, Protocols, NumProtocols); + ObjCObjectPointerType::Profile(ID, ObjectT); void *InsertPos = 0; - if (ObjCInterfaceType *QT = - ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) + if (ObjCObjectPointerType *QT = + ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); - // Sort the protocol list alphabetically to canonicalize it. + // Find the canonical object type. QualType Canonical; - if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) { - llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, - Protocols + NumProtocols); - - unsigned UniqueCount = NumProtocols; - SortAndUniqueProtocols(&Sorted[0], UniqueCount); + if (!ObjectT.isCanonical()) { + Canonical = getObjCObjectPointerType(getCanonicalType(ObjectT)); - Canonical = getObjCInterfaceType(Decl, &Sorted[0], UniqueCount); - - ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos); + // Regenerate InsertPos. + ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos); } - unsigned Size = sizeof(ObjCInterfaceType) - + NumProtocols * sizeof(ObjCProtocolDecl *); - void *Mem = Allocate(Size, TypeAlignment); - ObjCInterfaceType *QType = new (Mem) ObjCInterfaceType(Canonical, - const_cast<ObjCInterfaceDecl*>(Decl), - Protocols, - NumProtocols); + // No match. + void *Mem = Allocate(sizeof(ObjCObjectPointerType), TypeAlignment); + ObjCObjectPointerType *QType = + new (Mem) ObjCObjectPointerType(Canonical, ObjectT); Types.push_back(QType); - ObjCInterfaceTypes.InsertNode(QType, InsertPos); + ObjCObjectPointerTypes.InsertNode(QType, InsertPos); return QualType(QType, 0); } +/// getObjCInterfaceType - Return the unique reference to the type for the +/// specified ObjC interface decl. The list of protocols is optional. +QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) { + if (Decl->TypeForDecl) + return QualType(Decl->TypeForDecl, 0); + + // FIXME: redeclarations? + void *Mem = Allocate(sizeof(ObjCInterfaceType), TypeAlignment); + ObjCInterfaceType *T = new (Mem) ObjCInterfaceType(Decl); + Decl->TypeForDecl = T; + Types.push_back(T); + return QualType(T, 0); +} + /// getTypeOfExprType - Unlike many "get<Type>" functions, we can't unique /// TypeOfExprType AST's (since expression's are never shared). For example, /// multiple declarations that refer to "typeof(x)" all contain different @@ -2362,26 +2292,35 @@ CanQualType ASTContext::getCanonicalType(QualType T) { QualType ASTContext::getUnqualifiedArrayType(QualType T, Qualifiers &Quals) { Quals = T.getQualifiers(); - if (!isa<ArrayType>(T)) { + const ArrayType *AT = getAsArrayType(T); + if (!AT) { return T.getUnqualifiedType(); } - const ArrayType *AT = cast<ArrayType>(T); QualType Elt = AT->getElementType(); QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals); if (Elt == UnqualElt) return T; - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) { + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { return getConstantArrayType(UnqualElt, CAT->getSize(), CAT->getSizeModifier(), 0); } - if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) { + if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) { return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0); } - const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T); + if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT)) { + return getVariableArrayType(UnqualElt, + VAT->getSizeExpr() ? + VAT->getSizeExpr()->Retain() : 0, + VAT->getSizeModifier(), + VAT->getIndexTypeCVRQualifiers(), + VAT->getBracketsRange()); + } + + const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(AT); return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(), DSAT->getSizeModifier(), 0, SourceRange()); @@ -2716,6 +2655,9 @@ unsigned ASTContext::getIntegerRank(Type *T) { /// \returns the type this bit-field will promote to, or NULL if no /// promotion occurs. QualType ASTContext::isPromotableBitField(Expr *E) { + if (E->isTypeDependent() || E->isValueDependent()) + return QualType(); + FieldDecl *Field = E->getBitField(); if (!Field) return QualType(); @@ -2811,7 +2753,7 @@ CreateRecordDecl(ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC, QualType ASTContext::getCFConstantStringType() { if (!CFConstantStringTypeDecl) { CFConstantStringTypeDecl = - CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), &Idents.get("NSConstantString")); CFConstantStringTypeDecl->startDefinition(); @@ -2853,7 +2795,7 @@ void ASTContext::setCFConstantStringType(QualType T) { QualType ASTContext::getNSConstantStringType() { if (!NSConstantStringTypeDecl) { NSConstantStringTypeDecl = - CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), &Idents.get("__builtin_NSString")); NSConstantStringTypeDecl->startDefinition(); @@ -2892,7 +2834,7 @@ void ASTContext::setNSConstantStringType(QualType T) { QualType ASTContext::getObjCFastEnumerationStateType() { if (!ObjCFastEnumerationStateTypeDecl) { ObjCFastEnumerationStateTypeDecl = - CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), &Idents.get("__objcFastEnumerationState")); ObjCFastEnumerationStateTypeDecl->startDefinition(); @@ -2927,7 +2869,7 @@ QualType ASTContext::getBlockDescriptorType() { RecordDecl *T; // FIXME: Needs the FlagAppleBlock bit. - T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), &Idents.get("__block_descriptor")); T->startDefinition(); @@ -2972,7 +2914,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { RecordDecl *T; // FIXME: Needs the FlagAppleBlock bit. - T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), &Idents.get("__block_descriptor_withcopydispose")); T->startDefinition(); @@ -3044,7 +2986,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { llvm::raw_svector_ostream(Name) << "__Block_byref_" << ++UniqueBlockByRefTypeID << '_' << DeclName; RecordDecl *T; - T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), &Idents.get(Name.str())); T->startDefinition(); QualType Int32Ty = IntTy; @@ -3088,14 +3030,15 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { QualType ASTContext::getBlockParmType( bool BlockHasCopyDispose, - llvm::SmallVector<const Expr *, 8> &BlockDeclRefDecls) { + llvm::SmallVectorImpl<const Expr *> &Layout) { + // FIXME: Move up static unsigned int UniqueBlockParmTypeID = 0; llvm::SmallString<36> Name; llvm::raw_svector_ostream(Name) << "__block_literal_" << ++UniqueBlockParmTypeID; RecordDecl *T; - T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), &Idents.get(Name.str())); T->startDefinition(); QualType FieldTypes[] = { @@ -3125,22 +3068,28 @@ QualType ASTContext::getBlockParmType( T->addDecl(Field); } - for (size_t i = 0; i < BlockDeclRefDecls.size(); ++i) { - const Expr *E = BlockDeclRefDecls[i]; - const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); - clang::IdentifierInfo *Name = 0; - if (BDRE) { + for (unsigned i = 0; i < Layout.size(); ++i) { + const Expr *E = Layout[i]; + + QualType FieldType = E->getType(); + IdentifierInfo *FieldName = 0; + if (isa<CXXThisExpr>(E)) { + FieldName = &Idents.get("this"); + } else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E)) { const ValueDecl *D = BDRE->getDecl(); - Name = &Idents.get(D->getName()); + FieldName = D->getIdentifier(); + if (BDRE->isByRef()) + FieldType = BuildByRefType(D->getNameAsCString(), FieldType); + } else { + // Padding. + assert(isa<ConstantArrayType>(FieldType) && + isa<DeclRefExpr>(E) && + !cast<DeclRefExpr>(E)->getDecl()->getDeclName() && + "doesn't match characteristics of padding decl"); } - QualType FieldType = E->getType(); - - if (BDRE && BDRE->isByRef()) - FieldType = BuildByRefType(BDRE->getDecl()->getNameAsCString(), - FieldType); FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), - Name, FieldType, /*TInfo=*/0, + FieldName, FieldType, /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); Field->setAccess(AS_public); T->addDecl(Field); @@ -3593,6 +3542,17 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // Anonymous structures print as '?' if (const IdentifierInfo *II = RDecl->getIdentifier()) { S += II->getName(); + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size(), + (*this).PrintingPolicy); + + S += TemplateArgsStr; + } } else { S += '?'; } @@ -3636,6 +3596,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } + // Ignore protocol qualifiers when mangling at this level. + if (const ObjCObjectType *OT = T->getAs<ObjCObjectType>()) + T = OT->getBaseType(); + if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) { // @encode(class_name) ObjCInterfaceDecl *OI = OIT->getDecl(); @@ -3718,6 +3682,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } + // gcc just blithely ignores member pointers. + // TODO: maybe there should be a mangling for these + if (T->getAs<MemberPointerType>()) + return; + assert(0 && "@encode for type not implemented!"); } @@ -4106,18 +4075,21 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, /// bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT) { + const ObjCObjectType* LHS = LHSOPT->getObjectType(); + const ObjCObjectType* RHS = RHSOPT->getObjectType(); + // If either type represents the built-in 'id' or 'Class' types, return true. - if (LHSOPT->isObjCBuiltinType() || RHSOPT->isObjCBuiltinType()) + if (LHS->isObjCUnqualifiedIdOrClass() || + RHS->isObjCUnqualifiedIdOrClass()) return true; - if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) + if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), QualType(RHSOPT,0), false); - const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); - const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); - if (LHS && RHS) // We have 2 user-defined types. + // If we have 2 user-defined types, fall into that path. + if (LHS->getInterface() && RHS->getInterface()) return canAssignObjCInterfaces(LHS, RHS); return false; @@ -4168,8 +4140,10 @@ void getIntersectionOfProtocols(ASTContext &Context, const ObjCObjectPointerType *RHSOPT, llvm::SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) { - const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); - const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + const ObjCObjectType* LHS = LHSOPT->getObjectType(); + const ObjCObjectType* RHS = RHSOPT->getObjectType(); + assert(LHS->getInterface() && "LHS must have an interface base"); + assert(RHS->getInterface() && "RHS must have an interface base"); llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet; unsigned LHSNumProtocols = LHS->getNumProtocols(); @@ -4177,7 +4151,8 @@ void getIntersectionOfProtocols(ASTContext &Context, InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end()); else { llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols; - Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols); + Context.CollectInheritedProtocols(LHS->getInterface(), + LHSInheritedProtocols); InheritedProtocolSet.insert(LHSInheritedProtocols.begin(), LHSInheritedProtocols.end()); } @@ -4192,7 +4167,8 @@ void getIntersectionOfProtocols(ASTContext &Context, } else { llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols; - Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols); + Context.CollectInheritedProtocols(RHS->getInterface(), + RHSInheritedProtocols); for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = RHSInheritedProtocols.begin(), E = RHSInheritedProtocols.end(); I != E; ++I) @@ -4206,37 +4182,40 @@ void getIntersectionOfProtocols(ASTContext &Context, /// last type comparison in a ?-exp of ObjC pointer types before a /// warning is issued. So, its invokation is extremely rare. QualType ASTContext::areCommonBaseCompatible( - const ObjCObjectPointerType *LHSOPT, - const ObjCObjectPointerType *RHSOPT) { - const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); - const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); - if (!LHS || !RHS) + const ObjCObjectPointerType *Lptr, + const ObjCObjectPointerType *Rptr) { + const ObjCObjectType *LHS = Lptr->getObjectType(); + const ObjCObjectType *RHS = Rptr->getObjectType(); + const ObjCInterfaceDecl* LDecl = LHS->getInterface(); + const ObjCInterfaceDecl* RDecl = RHS->getInterface(); + if (!LDecl || !RDecl) return QualType(); - while (const ObjCInterfaceDecl *LHSIDecl = LHS->getDecl()->getSuperClass()) { - QualType LHSTy = getObjCInterfaceType(LHSIDecl); - LHS = LHSTy->getAs<ObjCInterfaceType>(); + while ((LDecl = LDecl->getSuperClass())) { + LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl)); if (canAssignObjCInterfaces(LHS, RHS)) { - llvm::SmallVector<ObjCProtocolDecl *, 8> IntersectionOfProtocols; - getIntersectionOfProtocols(*this, - LHSOPT, RHSOPT, IntersectionOfProtocols); - if (IntersectionOfProtocols.empty()) - LHSTy = getObjCObjectPointerType(LHSTy); - else - LHSTy = getObjCObjectPointerType(LHSTy, &IntersectionOfProtocols[0], - IntersectionOfProtocols.size()); - return LHSTy; + llvm::SmallVector<ObjCProtocolDecl *, 8> Protocols; + getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols); + + QualType Result = QualType(LHS, 0); + if (!Protocols.empty()) + Result = getObjCObjectType(Result, Protocols.data(), Protocols.size()); + Result = getObjCObjectPointerType(Result); + return Result; } } return QualType(); } -bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, - const ObjCInterfaceType *RHS) { +bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, + const ObjCObjectType *RHS) { + assert(LHS->getInterface() && "LHS is not an interface type"); + assert(RHS->getInterface() && "RHS is not an interface type"); + // Verify that the base decls are compatible: the RHS must be a subclass of // the LHS. - if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl())) + if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface())) return false; // RHS must have a superset of the protocols in the LHS. If the LHS is not @@ -4249,15 +4228,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, if (RHS->getNumProtocols() == 0) return true; // FIXME: should return false! - for (ObjCInterfaceType::qual_iterator LHSPI = LHS->qual_begin(), - LHSPE = LHS->qual_end(); + for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(), + LHSPE = LHS->qual_end(); LHSPI != LHSPE; LHSPI++) { bool RHSImplementsProtocol = false; // If the RHS doesn't implement the protocol on the left, the types // are incompatible. - for (ObjCInterfaceType::qual_iterator RHSPI = RHS->qual_begin(), - RHSPE = RHS->qual_end(); + for (ObjCObjectType::qual_iterator RHSPI = RHS->qual_begin(), + RHSPE = RHS->qual_end(); RHSPI != RHSPE; RHSPI++) { if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) { RHSImplementsProtocol = true; @@ -4483,6 +4462,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, if (RHSClass == Type::VariableArray || RHSClass == Type::IncompleteArray) RHSClass = Type::ConstantArray; + // ObjCInterfaces are just specialized ObjCObjects. + if (LHSClass == Type::ObjCInterface) LHSClass = Type::ObjCObject; + if (RHSClass == Type::ObjCInterface) RHSClass = Type::ObjCObject; + // Canonicalize ExtVector -> Vector. if (LHSClass == Type::ExtVector) LHSClass = Type::Vector; if (RHSClass == Type::ExtVector) RHSClass = Type::Vector; @@ -4522,6 +4505,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, assert(false && "C++ should never be in mergeTypes"); return QualType(); + case Type::ObjCInterface: case Type::IncompleteArray: case Type::VariableArray: case Type::FunctionProto: @@ -4614,14 +4598,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, RHSCan->getAs<VectorType>())) return LHS; return QualType(); - case Type::ObjCInterface: { - // Check if the interfaces are assignment compatible. + case Type::ObjCObject: { + // Check if the types are assignment compatible. // FIXME: This should be type compatibility, e.g. whether // "LHS x; RHS x;" at global scope is legal. - const ObjCInterfaceType* LHSIface = LHS->getAs<ObjCInterfaceType>(); - const ObjCInterfaceType* RHSIface = RHS->getAs<ObjCInterfaceType>(); - if (LHSIface && RHSIface && - canAssignObjCInterfaces(LHSIface, RHSIface)) + const ObjCObjectType* LHSIface = LHS->getAs<ObjCObjectType>(); + const ObjCObjectType* RHSIface = RHS->getAs<ObjCObjectType>(); + if (canAssignObjCInterfaces(LHSIface, RHSIface)) return LHS; return QualType(); @@ -4645,6 +4628,87 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, return QualType(); } +/// mergeObjCGCQualifiers - This routine merges ObjC's GC attribute of 'LHS' and +/// 'RHS' attributes and returns the merged version; including for function +/// return types. +QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { + QualType LHSCan = getCanonicalType(LHS), + RHSCan = getCanonicalType(RHS); + // If two types are identical, they are compatible. + if (LHSCan == RHSCan) + return LHS; + if (RHSCan->isFunctionType()) { + if (!LHSCan->isFunctionType()) + return QualType(); + QualType OldReturnType = + cast<FunctionType>(RHSCan.getTypePtr())->getResultType(); + QualType NewReturnType = + cast<FunctionType>(LHSCan.getTypePtr())->getResultType(); + QualType ResReturnType = + mergeObjCGCQualifiers(NewReturnType, OldReturnType); + if (ResReturnType.isNull()) + return QualType(); + if (ResReturnType == NewReturnType || ResReturnType == OldReturnType) { + // id foo(); ... __strong id foo(); or: __strong id foo(); ... id foo(); + // In either case, use OldReturnType to build the new function type. + const FunctionType *F = LHS->getAs<FunctionType>(); + if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) { + FunctionType::ExtInfo Info = getFunctionExtInfo(LHS); + QualType ResultType + = getFunctionType(OldReturnType, FPT->arg_type_begin(), + FPT->getNumArgs(), FPT->isVariadic(), + FPT->getTypeQuals(), + FPT->hasExceptionSpec(), + FPT->hasAnyExceptionSpec(), + FPT->getNumExceptions(), + FPT->exception_begin(), + Info); + return ResultType; + } + } + return QualType(); + } + + // If the qualifiers are different, the types can still be merged. + Qualifiers LQuals = LHSCan.getLocalQualifiers(); + Qualifiers RQuals = RHSCan.getLocalQualifiers(); + if (LQuals != RQuals) { + // If any of these qualifiers are different, we have a type mismatch. + if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || + LQuals.getAddressSpace() != RQuals.getAddressSpace()) + return QualType(); + + // Exactly one GC qualifier difference is allowed: __strong is + // okay if the other type has no GC qualifier but is an Objective + // C object pointer (i.e. implicitly strong by default). We fix + // this by pretending that the unqualified type was actually + // qualified __strong. + Qualifiers::GC GC_L = LQuals.getObjCGCAttr(); + Qualifiers::GC GC_R = RQuals.getObjCGCAttr(); + assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements"); + + if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak) + return QualType(); + + if (GC_L == Qualifiers::Strong) + return LHS; + if (GC_R == Qualifiers::Strong) + return RHS; + return QualType(); + } + + if (LHSCan->isObjCObjectPointerType() && RHSCan->isObjCObjectPointerType()) { + QualType LHSBaseQT = LHS->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType RHSBaseQT = RHS->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType ResQT = mergeObjCGCQualifiers(LHSBaseQT, RHSBaseQT); + if (ResQT == LHSBaseQT) + return LHS; + if (ResQT == RHSBaseQT) + return RHS; + } + return QualType(); +} + //===----------------------------------------------------------------------===// // Integer Predicates //===----------------------------------------------------------------------===// diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index e4cd2a9c1053..0d609bfa6d39 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -19,65 +19,41 @@ using namespace clang; -/// Determines whether we should have an a.k.a. clause when -/// pretty-printing a type. There are three main criteria: -/// -/// 1) Some types provide very minimal sugar that doesn't impede the -/// user's understanding --- for example, elaborated type -/// specifiers. If this is all the sugar we see, we don't want an -/// a.k.a. clause. -/// 2) Some types are technically sugared but are much more familiar -/// when seen in their sugared form --- for example, va_list, -/// vector types, and the magic Objective C types. We don't -/// want to desugar these, even if we do produce an a.k.a. clause. -/// 3) Some types may have already been desugared previously in this diagnostic. -/// if this is the case, doing another "aka" would just be clutter. -/// -static bool ShouldAKA(ASTContext &Context, QualType QT, - const Diagnostic::ArgumentValue *PrevArgs, - unsigned NumPrevArgs, - QualType &DesugaredQT) { - QualType InputTy = QT; - - bool AKA = false; - QualifierCollector Qc; - +// Returns a desugared version of the QualType, and marks ShouldAKA as true +// whenever we remove significant sugar from the type. +static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { + QualifierCollector QC; + while (true) { - const Type *Ty = Qc.strip(QT); - + const Type *Ty = QC.strip(QT); + // Don't aka just because we saw an elaborated type... if (isa<ElaboratedType>(Ty)) { QT = cast<ElaboratedType>(Ty)->desugar(); continue; } - - // ...or a qualified name type... - if (isa<QualifiedNameType>(Ty)) { - QT = cast<QualifiedNameType>(Ty)->desugar(); - continue; - } // ...or a substituted template type parameter. if (isa<SubstTemplateTypeParmType>(Ty)) { QT = cast<SubstTemplateTypeParmType>(Ty)->desugar(); continue; } - + // Don't desugar template specializations. if (isa<TemplateSpecializationType>(Ty)) break; - + // Don't desugar magic Objective-C types. if (QualType(Ty,0) == Context.getObjCIdType() || QualType(Ty,0) == Context.getObjCClassType() || QualType(Ty,0) == Context.getObjCSelType() || QualType(Ty,0) == Context.getObjCProtoType()) break; - + // Don't desugar va_list. if (QualType(Ty,0) == Context.getBuiltinVaListType()) break; - + // Otherwise, do a single-step desugar. QualType Underlying; bool IsSugar = false; @@ -94,50 +70,56 @@ break; \ } #include "clang/AST/TypeNodes.def" } - + // If it wasn't sugared, we're done. if (!IsSugar) break; - + // If the desugared type is a vector type, we don't want to expand // it, it will turn into an attribute mess. People want their "vec4". if (isa<VectorType>(Underlying)) break; - + // Don't desugar through the primary typedef of an anonymous type. if (isa<TagType>(Underlying) && isa<TypedefType>(QT)) if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() == cast<TypedefType>(QT)->getDecl()) break; - - // Otherwise, we're tearing through something opaque; note that - // we'll eventually need an a.k.a. clause and keep going. - AKA = true; + + // Record that we actually looked through an opaque type here. + ShouldAKA = true; QT = Underlying; - continue; } - - // If we never tore through opaque sugar, don't print aka. - if (!AKA) return false; - - // If we did, check to see if we already desugared this type in this - // diagnostic. If so, don't do it again. - for (unsigned i = 0; i != NumPrevArgs; ++i) { - // TODO: Handle ak_declcontext case. - if (PrevArgs[i].first == Diagnostic::ak_qualtype) { - void *Ptr = (void*)PrevArgs[i].second; - QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); - if (PrevTy == InputTy) - return false; - } + + // If we have a pointer-like type, desugar the pointee as well. + // FIXME: Handle other pointer-like types. + if (const PointerType *Ty = QT->getAs<PointerType>()) { + QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); + } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { + QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); } - - DesugaredQT = Qc.apply(QT); - return true; + + return QC.apply(QT); } /// \brief Convert the given type to a string suitable for printing as part of -/// a diagnostic. +/// a diagnostic. +/// +/// There are three main criteria when determining whether we should have an +/// a.k.a. clause when pretty-printing a type: +/// +/// 1) Some types provide very minimal sugar that doesn't impede the +/// user's understanding --- for example, elaborated type +/// specifiers. If this is all the sugar we see, we don't want an +/// a.k.a. clause. +/// 2) Some types are technically sugared but are much more familiar +/// when seen in their sugared form --- for example, va_list, +/// vector types, and the magic Objective C types. We don't +/// want to desugar these, even if we do produce an a.k.a. clause. +/// 3) Some types may have already been desugared previously in this diagnostic. +/// if this is the case, doing another "aka" would just be clutter. /// /// \param Context the context in which the type was allocated /// \param Ty the type to print @@ -147,18 +129,35 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, unsigned NumPrevArgs) { // FIXME: Playing with std::string is really slow. std::string S = Ty.getAsString(Context.PrintingPolicy); - + + // Check to see if we already desugared this type in this + // diagnostic. If so, don't do it again. + bool Repeated = false; + for (unsigned i = 0; i != NumPrevArgs; ++i) { + // TODO: Handle ak_declcontext case. + if (PrevArgs[i].first == Diagnostic::ak_qualtype) { + void *Ptr = (void*)PrevArgs[i].second; + QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); + if (PrevTy == Ty) { + Repeated = true; + break; + } + } + } + // Consider producing an a.k.a. clause if removing all the direct // sugar gives us something "significantly different". - - QualType DesugaredTy; - if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) { - S = "'"+S+"' (aka '"; - S += DesugaredTy.getAsString(Context.PrintingPolicy); - S += "')"; - return S; + if (!Repeated) { + bool ShouldAKA = false; + QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA); + if (ShouldAKA) { + S = "'"+S+"' (aka '"; + S += DesugaredTy.getAsString(Context.PrintingPolicy); + S += "')"; + return S; + } } - + S = "'" + S + "'"; return S; } diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index ae09d7978ea5..6ed08d1e1e29 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -68,13 +68,13 @@ namespace { // FIXME: DependentDecltypeType QualType VisitRecordType(RecordType *T); QualType VisitEnumType(EnumType *T); - QualType VisitElaboratedType(ElaboratedType *T); // FIXME: TemplateTypeParmType // FIXME: SubstTemplateTypeParmType // FIXME: TemplateSpecializationType - QualType VisitQualifiedNameType(QualifiedNameType *T); + QualType VisitElaboratedType(ElaboratedType *T); // FIXME: DependentNameType QualType VisitObjCInterfaceType(ObjCInterfaceType *T); + QualType VisitObjCObjectType(ObjCObjectType *T); QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T); // Importing declarations @@ -532,19 +532,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, cast<TagType>(T2)->getDecl())) return false; break; - - case Type::Elaborated: { - const ElaboratedType *Elab1 = cast<ElaboratedType>(T1); - const ElaboratedType *Elab2 = cast<ElaboratedType>(T2); - if (Elab1->getTagKind() != Elab2->getTagKind()) - return false; - if (!IsStructurallyEquivalent(Context, - Elab1->getUnderlyingType(), - Elab2->getUnderlyingType())) - return false; - break; - } - + case Type::TemplateTypeParm: { const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1); const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2); @@ -594,16 +582,19 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } - case Type::QualifiedName: { - const QualifiedNameType *Qual1 = cast<QualifiedNameType>(T1); - const QualifiedNameType *Qual2 = cast<QualifiedNameType>(T2); + case Type::Elaborated: { + const ElaboratedType *Elab1 = cast<ElaboratedType>(T1); + const ElaboratedType *Elab2 = cast<ElaboratedType>(T2); + // CHECKME: what if a keyword is ETK_None or ETK_typename ? + if (Elab1->getKeyword() != Elab2->getKeyword()) + return false; if (!IsStructurallyEquivalent(Context, - Qual1->getQualifier(), - Qual2->getQualifier())) + Elab1->getQualifier(), + Elab2->getQualifier())) return false; if (!IsStructurallyEquivalent(Context, - Qual1->getNamedType(), - Qual2->getNamedType())) + Elab1->getNamedType(), + Elab2->getNamedType())) return false; break; } @@ -642,12 +633,22 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, Iface1->getDecl(), Iface2->getDecl())) return false; - if (Iface1->getNumProtocols() != Iface2->getNumProtocols()) + break; + } + + case Type::ObjCObject: { + const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1); + const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2); + if (!IsStructurallyEquivalent(Context, + Obj1->getBaseType(), + Obj2->getBaseType())) + return false; + if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) return false; - for (unsigned I = 0, N = Iface1->getNumProtocols(); I != N; ++I) { + for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { if (!IsStructurallyEquivalent(Context, - Iface1->getProtocol(I), - Iface2->getProtocol(I))) + Obj1->getProtocol(I), + Obj2->getProtocol(I))) return false; } break; @@ -660,14 +661,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Ptr1->getPointeeType(), Ptr2->getPointeeType())) return false; - if (Ptr1->getNumProtocols() != Ptr2->getNumProtocols()) - return false; - for (unsigned I = 0, N = Ptr1->getNumProtocols(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Ptr1->getProtocol(I), - Ptr2->getProtocol(I))) - return false; - } break; } @@ -1293,24 +1286,20 @@ QualType ASTNodeImporter::VisitEnumType(EnumType *T) { } QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) { - QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); - if (ToUnderlyingType.isNull()) - return QualType(); - - return Importer.getToContext().getElaboratedType(ToUnderlyingType, - T->getTagKind()); -} - -QualType ASTNodeImporter::VisitQualifiedNameType(QualifiedNameType *T) { - NestedNameSpecifier *ToQualifier = Importer.Import(T->getQualifier()); - if (!ToQualifier) - return QualType(); + NestedNameSpecifier *ToQualifier = 0; + // Note: the qualifier in an ElaboratedType is optional. + if (T->getQualifier()) { + ToQualifier = Importer.Import(T->getQualifier()); + if (!ToQualifier) + return QualType(); + } QualType ToNamedType = Importer.Import(T->getNamedType()); if (ToNamedType.isNull()) return QualType(); - return Importer.getToContext().getQualifiedNameType(ToQualifier, ToNamedType); + return Importer.getToContext().getElaboratedType(T->getKeyword(), + ToQualifier, ToNamedType); } QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) { @@ -1319,8 +1308,16 @@ QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) { if (!Class) return QualType(); + return Importer.getToContext().getObjCInterfaceType(Class); +} + +QualType ASTNodeImporter::VisitObjCObjectType(ObjCObjectType *T) { + QualType ToBaseType = Importer.Import(T->getBaseType()); + if (ToBaseType.isNull()) + return QualType(); + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; - for (ObjCInterfaceType::qual_iterator P = T->qual_begin(), + for (ObjCObjectType::qual_iterator P = T->qual_begin(), PEnd = T->qual_end(); P != PEnd; ++P) { ObjCProtocolDecl *Protocol @@ -1330,9 +1327,9 @@ QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) { Protocols.push_back(Protocol); } - return Importer.getToContext().getObjCInterfaceType(Class, - Protocols.data(), - Protocols.size()); + return Importer.getToContext().getObjCObjectType(ToBaseType, + Protocols.data(), + Protocols.size()); } QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) { @@ -1340,20 +1337,7 @@ QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) { if (ToPointeeType.isNull()) return QualType(); - llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; - for (ObjCObjectPointerType::qual_iterator P = T->qual_begin(), - PEnd = T->qual_end(); - P != PEnd; ++P) { - ObjCProtocolDecl *Protocol - = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P)); - if (!Protocol) - return QualType(); - Protocols.push_back(Protocol); - } - - return Importer.getToContext().getObjCObjectPointerType(ToPointeeType, - Protocols.data(), - Protocols.size()); + return Importer.getToContext().getObjCObjectPointerType(ToPointeeType); } //---------------------------------------------------------------------------- @@ -1617,7 +1601,12 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { D2->startDefinition(); ImportDeclContext(D); - D2->completeDefinition(T, ToPromotionType); + + // FIXME: we might need to merge the number of positive or negative bits + // if the enumerator lists don't match. + D2->completeDefinition(T, ToPromotionType, + D->getNumPositiveBits(), + D->getNumNegativeBits()); } return D2; @@ -2961,7 +2950,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { return 0; return ToContext.getTrivialTypeSourceInfo(T, - FromTSI->getTypeLoc().getFullSourceRange().getBegin()); + FromTSI->getTypeLoc().getSourceRange().getBegin()); } Decl *ASTImporter::Import(Decl *FromD) { diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index 423aa065e57c..0fab22caced8 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -74,6 +74,7 @@ void NonNullAttr::Destroy(ASTContext &C) { // FIXME: Can we use variadic macro to define DEF_SIMPLE_ATTR_CLONE for // "non-simple" classes? +DEF_SIMPLE_ATTR_CLONE(AlignMac68k) DEF_SIMPLE_ATTR_CLONE(AlwaysInline) DEF_SIMPLE_ATTR_CLONE(AnalyzerNoReturn) DEF_SIMPLE_ATTR_CLONE(BaseCheck) @@ -100,6 +101,7 @@ DEF_SIMPLE_ATTR_CLONE(Override) DEF_SIMPLE_ATTR_CLONE(Packed) DEF_SIMPLE_ATTR_CLONE(Pure) DEF_SIMPLE_ATTR_CLONE(StdCall) +DEF_SIMPLE_ATTR_CLONE(ThisCall) DEF_SIMPLE_ATTR_CLONE(TransparentUnion) DEF_SIMPLE_ATTR_CLONE(Unavailable) DEF_SIMPLE_ATTR_CLONE(Unused) @@ -110,8 +112,8 @@ DEF_SIMPLE_ATTR_CLONE(WeakImport) DEF_SIMPLE_ATTR_CLONE(WeakRef) DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer) -Attr* PragmaPackAttr::clone(ASTContext &C) const { - return ::new (C) PragmaPackAttr(Alignment); +Attr* MaxFieldAlignmentAttr::clone(ASTContext &C) const { + return ::new (C) MaxFieldAlignmentAttr(Alignment); } Attr* AlignedAttr::clone(ASTContext &C) const { @@ -142,6 +144,10 @@ Attr *IBOutletAttr::clone(ASTContext &C) const { return ::new (C) IBOutletAttr; } +Attr *IBOutletCollectionAttr::clone(ASTContext &C) const { + return ::new (C) IBOutletCollectionAttr(D); +} + Attr *IBActionAttr::clone(ASTContext &C) const { return ::new (C) IBActionAttr; } diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 91aaddc9a481..bce3646feedb 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -39,4 +39,4 @@ add_clang_library(clangAST TypePrinter.cpp ) -add_dependencies(clangAST ClangDiagnosticAST) +add_dependencies(clangAST ClangDiagnosticAST ClangStmtNodes) diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index a9f223045864..d616e42e0076 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -49,9 +49,8 @@ CXXBasePaths::decl_iterator CXXBasePaths::found_decls_end() { /// ambiguous, i.e., there are two or more paths that refer to /// different base class subobjects of the same type. BaseType must be /// an unqualified, canonical class type. -bool CXXBasePaths::isAmbiguous(QualType BaseType) { - assert(BaseType.isCanonical() && "Base type must be the canonical type"); - assert(BaseType.hasQualifiers() == 0 && "Base type must be unqualified"); +bool CXXBasePaths::isAmbiguous(CanQualType BaseType) { + BaseType = BaseType.getUnqualifiedType(); std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; return Subobjects.second + (Subobjects.first? 1 : 0) > 1; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ffe49671d8a3..ffdcb471d082 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -23,16 +23,11 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" -#include "clang/Parse/DeclSpec.h" +#include "clang/Basic/Specifiers.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; -/// \brief Return the TypeLoc wrapper for the type source info. -TypeLoc TypeSourceInfo::getTypeLoc() const { - return TypeLoc(Ty, (void*)(this + 1)); -} - //===----------------------------------------------------------------------===// // NamedDecl Implementation //===----------------------------------------------------------------------===// @@ -541,7 +536,7 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { while (true) { TypeLoc NextTL = TL.getNextTypeLoc(); if (!NextTL) - return TL.getSourceRange().getBegin(); + return TL.getLocalSourceRange().getBegin(); TL = NextTL; } } @@ -1224,9 +1219,8 @@ FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD, } bool FunctionDecl::isImplicitlyInstantiable() const { - // If this function already has a definition or is invalid, it can't be - // implicitly instantiated. - if (isInvalidDecl() || getBody()) + // If the function is invalid, it can't be implicitly instantiated. + if (isInvalidDecl()) return false; switch (getTemplateSpecializationKind()) { @@ -1295,11 +1289,22 @@ FunctionDecl::getTemplateSpecializationArgs() const { return 0; } +const TemplateArgumentListInfo * +FunctionDecl::getTemplateSpecializationArgsAsWritten() const { + if (FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo*>()) { + return Info->TemplateArgumentsAsWritten; + } + return 0; +} + void FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, void *InsertPos, - TemplateSpecializationKind TSK) { + TemplateSpecializationKind TSK, + const TemplateArgumentListInfo *TemplateArgsAsWritten) { assert(TSK != TSK_Undeclared && "Must specify the type of function template specialization"); FunctionTemplateSpecializationInfo *Info @@ -1311,6 +1316,7 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, Info->Template.setPointer(Template); Info->Template.setInt(TSK - 1); Info->TemplateArguments = TemplateArgs; + Info->TemplateArgumentsAsWritten = TemplateArgsAsWritten; TemplateOrSpecialization = Info; // Insert this function template specialization into the set of known @@ -1475,6 +1481,12 @@ TagDecl* TagDecl::getCanonicalDecl() { return getFirstDeclaration(); } +void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) { + TypedefDeclOrQualifier = TDD; + if (TypeForDecl) + TypeForDecl->ClearLinkageCache(); +} + void TagDecl::startDefinition() { if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) { TagT->decl.setPointer(this); @@ -1509,6 +1521,7 @@ void TagDecl::completeDefinition() { TypeForDecl->getAs<InjectedClassNameType>())) { assert(Injected->Decl == this && "Attempt to redefine a class template definition?"); + (void)Injected; } } @@ -1524,16 +1537,6 @@ TagDecl* TagDecl::getDefinition() const { return 0; } -TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) { - switch (TypeSpec) { - default: llvm_unreachable("unexpected type specifier"); - case DeclSpec::TST_struct: return TK_struct; - case DeclSpec::TST_class: return TK_class; - case DeclSpec::TST_union: return TK_union; - case DeclSpec::TST_enum: return TK_enum; - } -} - void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier, SourceRange QualifierRange) { if (Qualifier) { @@ -1571,10 +1574,14 @@ void EnumDecl::Destroy(ASTContext& C) { } void EnumDecl::completeDefinition(QualType NewType, - QualType NewPromotionType) { + QualType NewPromotionType, + unsigned NumPositiveBits, + unsigned NumNegativeBits) { assert(!isDefinition() && "Cannot redefine enums!"); IntegerType = NewType; PromotionType = NewPromotionType; + setNumPositiveBits(NumPositiveBits); + setNumNegativeBits(NumNegativeBits); TagDecl::completeDefinition(); } @@ -1620,6 +1627,17 @@ void RecordDecl::completeDefinition() { TagDecl::completeDefinition(); } +ValueDecl *RecordDecl::getAnonymousStructOrUnionObject() { + // Force the decl chain to come into existence properly. + if (!getNextDeclInContext()) getParent()->decls_begin(); + + assert(isAnonymousStructOrUnion()); + ValueDecl *D = cast<ValueDecl>(getNextDeclInContext()); + assert(D->getType()->isRecordType()); + assert(D->getType()->getAs<RecordType>()->getDecl() == this); + return D; +} + //===----------------------------------------------------------------------===// // BlockDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index b5aec0c5125c..42a372632099 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -811,12 +811,12 @@ DeclContext::lookup(DeclarationName Name) { buildLookup(this); if (!LookupPtr) - return lookup_result(0, 0); + return lookup_result(lookup_iterator(0), lookup_iterator(0)); } StoredDeclsMap::iterator Pos = LookupPtr->find(Name); if (Pos == LookupPtr->end()) - return lookup_result(0, 0); + return lookup_result(lookup_iterator(0), lookup_iterator(0)); return Pos->second.getLookupResult(getParentASTContext()); } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 68f4a821e689..cd7afd98b63d 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -137,7 +137,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().VBases[I] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, - VBaseClassDecl->getTagKind() == RecordDecl::TK_class, + VBaseClassDecl->getTagKind() == TTK_Class, VBases[I]->getAccessSpecifier(), VBaseType); } } @@ -700,8 +700,9 @@ CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual, SourceLocation L, Expr *Init, SourceLocation R) - : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), IsVirtual(IsVirtual), - LParenLoc(L), RParenLoc(R) + : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), + LParenLoc(L), RParenLoc(R), IsVirtual(IsVirtual), IsWritten(false), + SourceOrderOrNumArrayIndices(0) { } @@ -709,14 +710,46 @@ CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, SourceLocation L, Expr *Init, SourceLocation R) + : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init), + AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false), + IsWritten(false), SourceOrderOrNumArrayIndices(0) +{ +} + +CXXBaseOrMemberInitializer:: +CXXBaseOrMemberInitializer(ASTContext &Context, + FieldDecl *Member, SourceLocation MemberLoc, + SourceLocation L, Expr *Init, SourceLocation R, + VarDecl **Indices, + unsigned NumIndices) : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init), - AnonUnionMember(0), LParenLoc(L), RParenLoc(R) + AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false), + IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices) { + VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1); + memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *)); +} + +CXXBaseOrMemberInitializer * +CXXBaseOrMemberInitializer::Create(ASTContext &Context, + FieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, + Expr *Init, + SourceLocation R, + VarDecl **Indices, + unsigned NumIndices) { + void *Mem = Context.Allocate(sizeof(CXXBaseOrMemberInitializer) + + sizeof(VarDecl *) * NumIndices, + llvm::alignof<CXXBaseOrMemberInitializer>()); + return new (Mem) CXXBaseOrMemberInitializer(Context, Member, MemberLoc, + L, Init, R, Indices, NumIndices); } void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) { if (Init) Init->Destroy(Context); + // FIXME: Destroy indices this->~CXXBaseOrMemberInitializer(); } @@ -745,7 +778,7 @@ SourceLocation CXXBaseOrMemberInitializer::getSourceLocation() const { if (isMemberInitializer()) return getMemberLocation(); - return getBaseClassLoc().getSourceRange().getBegin(); + return getBaseClassLoc().getLocalSourceRange().getBegin(); } SourceRange CXXBaseOrMemberInitializer::getSourceRange() const { @@ -753,6 +786,12 @@ SourceRange CXXBaseOrMemberInitializer::getSourceRange() const { } CXXConstructorDecl * +CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationName(), + QualType(), 0, false, false, false); +} + +CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, @@ -855,6 +894,12 @@ bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const { } CXXDestructorDecl * +CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) CXXDestructorDecl(0, SourceLocation(), DeclarationName(), + QualType(), false, false); +} + +CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isInline, @@ -871,6 +916,12 @@ CXXConstructorDecl::Destroy(ASTContext& C) { } CXXConversionDecl * +CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationName(), + QualType(), 0, false, false); +} + +CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, @@ -908,6 +959,12 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() { return cast_or_null<NamespaceDecl>(NominatedNamespace); } +void UsingDirectiveDecl::setNominatedNamespace(NamedDecl* ND) { + assert((isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) && + "expected a NamespaceDecl or NamespaceAliasDecl"); + NominatedNamespace = ND; +} + NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, SourceLocation AliasLoc, diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index c498dea17703..26e291c94f64 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -94,6 +94,10 @@ TemplateDecl::~TemplateDecl() { // FunctionTemplateDecl Implementation //===----------------------------------------------------------------------===// +void FunctionTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} + FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -129,8 +133,9 @@ FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() { First = First->getPreviousDeclaration(); if (First->CommonOrPrev.isNull()) { - // FIXME: Allocate with the ASTContext - First->CommonOrPrev = new Common; + Common *CommonPtr = new (getASTContext()) Common; + getASTContext().AddDeallocation(DeallocateCommon, CommonPtr); + First->CommonOrPrev = CommonPtr; } return First->CommonOrPrev.get<Common*>(); } @@ -139,6 +144,10 @@ FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() { // ClassTemplateDecl Implementation //===----------------------------------------------------------------------===// +void ClassTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} + ClassTemplateDecl *ClassTemplateDecl::getCanonicalDecl() { ClassTemplateDecl *Template = this; while (Template->getPreviousDeclaration()) @@ -156,8 +165,10 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, Common *CommonPtr; if (PrevDecl) CommonPtr = PrevDecl->CommonPtr; - else + else { CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + } return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl, CommonPtr); @@ -259,7 +270,7 @@ TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC, } SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const { - return DefaultArgument->getTypeLoc().getFullSourceRange().getBegin(); + return DefaultArgument->getTypeLoc().getSourceRange().getBegin(); } unsigned TemplateTypeParmDecl::getDepth() const { @@ -303,22 +314,14 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, // TemplateArgumentListBuilder Implementation //===----------------------------------------------------------------------===// -void TemplateArgumentListBuilder::Append(const TemplateArgument& Arg) { - switch (Arg.getKind()) { - default: break; - case TemplateArgument::Type: - assert(Arg.getAsType().isCanonical() && "Type must be canonical!"); - break; - } - - assert(NumFlatArgs < MaxFlatArgs && "Argument list builder is full!"); +void TemplateArgumentListBuilder::Append(const TemplateArgument &Arg) { + assert((Arg.getKind() != TemplateArgument::Type || + Arg.getAsType().isCanonical()) && "Type must be canonical!"); + assert(FlatArgs.size() < MaxFlatArgs && "Argument list builder is full!"); assert(!StructuredArgs && "Can't append arguments when an argument pack has been added!"); - if (!FlatArgs) - FlatArgs = new TemplateArgument[MaxFlatArgs]; - - FlatArgs[NumFlatArgs++] = Arg; + FlatArgs.push_back(Arg); } void TemplateArgumentListBuilder::BeginPack() { @@ -326,7 +329,7 @@ void TemplateArgumentListBuilder::BeginPack() { assert(!StructuredArgs && "Argument list already contains a pack!"); AddingToPack = true; - PackBeginIndex = NumFlatArgs; + PackBeginIndex = FlatArgs.size(); } void TemplateArgumentListBuilder::EndPack() { @@ -335,6 +338,7 @@ void TemplateArgumentListBuilder::EndPack() { AddingToPack = false; + // FIXME: This is a memory leak! StructuredArgs = new TemplateArgument[MaxStructuredArgs]; // First copy the flat entries over to the list (if any) @@ -346,22 +350,14 @@ void TemplateArgumentListBuilder::EndPack() { // Next, set the pack. TemplateArgument *PackArgs = 0; unsigned NumPackArgs = NumFlatArgs - PackBeginIndex; + // FIXME: NumPackArgs shouldn't be negative here??? if (NumPackArgs) - PackArgs = &FlatArgs[PackBeginIndex]; + PackArgs = FlatArgs.data()+PackBeginIndex; StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs, /*CopyArgs=*/false); } -void TemplateArgumentListBuilder::ReleaseArgs() { - FlatArgs = 0; - NumFlatArgs = 0; - MaxFlatArgs = 0; - StructuredArgs = 0; - NumStructuredArgs = 0; - MaxStructuredArgs = 0; -} - //===----------------------------------------------------------------------===// // TemplateArgumentList Implementation //===----------------------------------------------------------------------===// @@ -376,35 +372,56 @@ TemplateArgumentList::TemplateArgumentList(ASTContext &Context, if (!TakeArgs) return; - if (Builder.getStructuredArguments() == Builder.getFlatArguments()) + // If this does take ownership of the arguments, then we have to new them + // and copy over. + TemplateArgument *NewArgs = + new (Context) TemplateArgument[Builder.flatSize()]; + std::copy(Builder.getFlatArguments(), + Builder.getFlatArguments()+Builder.flatSize(), NewArgs); + FlatArguments.setPointer(NewArgs); + + // Just reuse the structured and flat arguments array if possible. + if (Builder.getStructuredArguments() == Builder.getFlatArguments()) { + StructuredArguments.setPointer(NewArgs); StructuredArguments.setInt(0); - Builder.ReleaseArgs(); + } else { + TemplateArgument *NewSArgs = + new (Context) TemplateArgument[Builder.flatSize()]; + std::copy(Builder.getFlatArguments(), + Builder.getFlatArguments()+Builder.flatSize(), NewSArgs); + StructuredArguments.setPointer(NewSArgs); + } } -TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList &Other) - : FlatArguments(Other.FlatArguments.getPointer(), 1), - NumFlatArguments(Other.flat_size()), - StructuredArguments(Other.StructuredArguments.getPointer(), 1), - NumStructuredArguments(Other.NumStructuredArguments) { } +/// Produces a shallow copy of the given template argument list. This +/// assumes that the input argument list outlives it. This takes the list as +/// a pointer to avoid looking like a copy constructor, since this really +/// really isn't safe to use that way. +TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList *Other) + : FlatArguments(Other->FlatArguments.getPointer(), false), + NumFlatArguments(Other->flat_size()), + StructuredArguments(Other->StructuredArguments.getPointer(), false), + NumStructuredArguments(Other->NumStructuredArguments) { } -TemplateArgumentList::~TemplateArgumentList() { - // FIXME: Deallocate template arguments +void TemplateArgumentList::Destroy(ASTContext &C) { + if (FlatArguments.getInt()) + C.Deallocate((void*)FlatArguments.getPointer()); + if (StructuredArguments.getInt()) + C.Deallocate((void*)StructuredArguments.getPointer()); } +TemplateArgumentList::~TemplateArgumentList() {} + //===----------------------------------------------------------------------===// // ClassTemplateSpecializationDecl Implementation //===----------------------------------------------------------------------===// ClassTemplateSpecializationDecl:: -ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, +ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, ClassTemplateSpecializationDecl *PrevDecl) - : CXXRecordDecl(DK, - SpecializedTemplate->getTemplatedDecl()->getTagKind(), - DC, L, - // FIXME: Should we use DeclarationName for the name of - // class template specializations? + : CXXRecordDecl(DK, TK, DC, L, SpecializedTemplate->getIdentifier(), PrevDecl), SpecializedTemplate(SpecializedTemplate), @@ -414,7 +431,7 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, } ClassTemplateSpecializationDecl * -ClassTemplateSpecializationDecl::Create(ASTContext &Context, +ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, @@ -422,7 +439,7 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, ClassTemplateSpecializationDecl *Result = new (Context)ClassTemplateSpecializationDecl(Context, ClassTemplateSpecialization, - DC, L, + TK, DC, L, SpecializedTemplate, Builder, PrevDecl); @@ -464,7 +481,7 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const { //===----------------------------------------------------------------------===// ClassTemplatePartialSpecializationDecl * ClassTemplatePartialSpecializationDecl:: -Create(ASTContext &Context, DeclContext *DC, SourceLocation L, +Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, @@ -478,7 +495,7 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, ClonedArgs[I] = ArgInfos[I]; ClassTemplatePartialSpecializationDecl *Result - = new (Context)ClassTemplatePartialSpecializationDecl(Context, + = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC, L, Params, SpecializedTemplate, Builder, diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 4f85fca53868..343d403e76ad 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -11,10 +11,11 @@ // classes. // //===----------------------------------------------------------------------===// +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeOrdering.h" -#include "clang/AST/Decl.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -383,12 +384,12 @@ void DeclarationName::dump() const { llvm::errs() << '\n'; } -DeclarationNameTable::DeclarationNameTable() { +DeclarationNameTable::DeclarationNameTable(ASTContext &C) : Ctx(C) { CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>; CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>; // Initialize the overloaded operator names. - CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS]; + CXXOperatorNames = new (Ctx) CXXOperatorIdName[NUM_OVERLOADED_OPERATORS]; for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) { CXXOperatorNames[Op].ExtraKindOrNumArgs = Op + DeclarationNameExtra::CXXConversionFunction; @@ -399,29 +400,32 @@ DeclarationNameTable::DeclarationNameTable() { DeclarationNameTable::~DeclarationNameTable() { llvm::FoldingSet<CXXSpecialName> *SpecialNames = static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl); - llvm::FoldingSetIterator<CXXSpecialName> - SI = SpecialNames->begin(), SE = SpecialNames->end(); + llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames + = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*> + (CXXLiteralOperatorNames); - while (SI != SE) { - CXXSpecialName *n = &*SI++; - delete n; - } + if (Ctx.FreeMemory) { + llvm::FoldingSetIterator<CXXSpecialName> + SI = SpecialNames->begin(), SE = SpecialNames->end(); + while (SI != SE) { + CXXSpecialName *n = &*SI++; + Ctx.Deallocate(n); + } - llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames - = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*> - (CXXLiteralOperatorNames); - llvm::FoldingSetIterator<CXXLiteralOperatorIdName> - LI = LiteralNames->begin(), LE = LiteralNames->end(); + llvm::FoldingSetIterator<CXXLiteralOperatorIdName> + LI = LiteralNames->begin(), LE = LiteralNames->end(); + + while (LI != LE) { + CXXLiteralOperatorIdName *n = &*LI++; + Ctx.Deallocate(n); + } - while (LI != LE) { - CXXLiteralOperatorIdName *n = &*LI++; - delete n; + Ctx.Deallocate(CXXOperatorNames); } delete SpecialNames; delete LiteralNames; - delete [] CXXOperatorNames; } DeclarationName @@ -459,7 +463,7 @@ DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, if (CXXSpecialName *Name = SpecialNames->FindNodeOrInsertPos(ID, InsertPos)) return DeclarationName(Name); - CXXSpecialName *SpecialName = new CXXSpecialName; + CXXSpecialName *SpecialName = new (Ctx) CXXSpecialName; SpecialName->ExtraKindOrNumArgs = EKind; SpecialName->Type = Ty; SpecialName->FETokenInfo = 0; @@ -487,7 +491,7 @@ DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) { LiteralNames->FindNodeOrInsertPos(ID, InsertPos)) return DeclarationName (Name); - CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName; + CXXLiteralOperatorIdName *LiteralName = new (Ctx) CXXLiteralOperatorIdName; LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator; LiteralName->ID = II; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 00662a53afed..c38cec32c3b2 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -27,6 +27,8 @@ #include <algorithm> using namespace clang; +void Expr::ANCHOR() {} // key function for Expr class. + /// isKnownToHaveBooleanValue - Return true if this is an integer expression /// that is known to return 0 or 1. This happens for _Bool/bool expressions /// but also int expressions which are produced by things like comparisons in @@ -161,8 +163,19 @@ void DeclRefExpr::computeDependence() { if (const Expr *Init = Var->getAnyInitializer()) if (Init->isValueDependent()) ValueDependent = true; - } - } + } + // (VD) - FIXME: Missing from the standard: + // - a member function or a static data member of the current + // instantiation + else if (Var->isStaticDataMember() && + Var->getDeclContext()->isDependentContext()) + ValueDependent = true; + } + // (VD) - FIXME: Missing from the standard: + // - a member function or a static data member of the current + // instantiation + else if (isa<CXXMethodDecl>(D) && D->getDeclContext()->isDependentContext()) + ValueDependent = true; // (TD) - a nested-name-specifier or a qualified-id that names a // member of an unknown specialization. // (handled by DependentScopeDeclRefExpr) @@ -976,6 +989,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return true; } case CompoundAssignOperatorClass: + case VAArgExprClass: return false; case ConditionalOperatorClass: { @@ -1557,6 +1571,18 @@ Expr *Expr::IgnoreParenCasts() { } } +Expr *Expr::IgnoreParenImpCasts() { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast<ParenExpr>(E)) + E = P->getSubExpr(); + else if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) + E = P->getSubExpr(); + else + return E; + } +} + /// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the /// value (including ptr->int casts of the same size). Strip off any /// ParenExpr or CastExprs, returning their operand. @@ -1757,385 +1783,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { return isEvaluatable(Ctx); } -/// isIntegerConstantExpr - this recursive routine will test if an expression is -/// an integer constant expression. - -/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero, -/// comma, etc -/// -/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof -/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer -/// cast+dereference. - -// CheckICE - This function does the fundamental ICE checking: the returned -// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation. -// Note that to reduce code duplication, this helper does no evaluation -// itself; the caller checks whether the expression is evaluatable, and -// in the rare cases where CheckICE actually cares about the evaluated -// value, it calls into Evalute. -// -// Meanings of Val: -// 0: This expression is an ICE if it can be evaluated by Evaluate. -// 1: This expression is not an ICE, but if it isn't evaluated, it's -// a legal subexpression for an ICE. This return value is used to handle -// the comma operator in C99 mode. -// 2: This expression is not an ICE, and is not a legal subexpression for one. - -struct ICEDiag { - unsigned Val; - SourceLocation Loc; - - public: - ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {} - ICEDiag() : Val(0) {} -}; - -ICEDiag NoDiag() { return ICEDiag(); } - -static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) { - Expr::EvalResult EVResult; - if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || - !EVResult.Val.isInt()) { - return ICEDiag(2, E->getLocStart()); - } - return NoDiag(); -} - -static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { - assert(!E->isValueDependent() && "Should not see value dependent exprs!"); - if (!E->getType()->isIntegralType()) { - return ICEDiag(2, E->getLocStart()); - } - - switch (E->getStmtClass()) { -#define STMT(Node, Base) case Expr::Node##Class: -#define EXPR(Node, Base) -#include "clang/AST/StmtNodes.def" - case Expr::PredefinedExprClass: - case Expr::FloatingLiteralClass: - case Expr::ImaginaryLiteralClass: - case Expr::StringLiteralClass: - case Expr::ArraySubscriptExprClass: - case Expr::MemberExprClass: - case Expr::CompoundAssignOperatorClass: - case Expr::CompoundLiteralExprClass: - case Expr::ExtVectorElementExprClass: - case Expr::InitListExprClass: - case Expr::DesignatedInitExprClass: - case Expr::ImplicitValueInitExprClass: - case Expr::ParenListExprClass: - case Expr::VAArgExprClass: - case Expr::AddrLabelExprClass: - case Expr::StmtExprClass: - case Expr::CXXMemberCallExprClass: - case Expr::CXXDynamicCastExprClass: - case Expr::CXXTypeidExprClass: - case Expr::CXXNullPtrLiteralExprClass: - case Expr::CXXThisExprClass: - case Expr::CXXThrowExprClass: - case Expr::CXXNewExprClass: - case Expr::CXXDeleteExprClass: - case Expr::CXXPseudoDestructorExprClass: - case Expr::UnresolvedLookupExprClass: - case Expr::DependentScopeDeclRefExprClass: - case Expr::CXXConstructExprClass: - case Expr::CXXBindTemporaryExprClass: - case Expr::CXXBindReferenceExprClass: - case Expr::CXXExprWithTemporariesClass: - case Expr::CXXTemporaryObjectExprClass: - case Expr::CXXUnresolvedConstructExprClass: - case Expr::CXXDependentScopeMemberExprClass: - case Expr::UnresolvedMemberExprClass: - case Expr::ObjCStringLiteralClass: - case Expr::ObjCEncodeExprClass: - case Expr::ObjCMessageExprClass: - case Expr::ObjCSelectorExprClass: - case Expr::ObjCProtocolExprClass: - case Expr::ObjCIvarRefExprClass: - case Expr::ObjCPropertyRefExprClass: - case Expr::ObjCImplicitSetterGetterRefExprClass: - case Expr::ObjCSuperExprClass: - case Expr::ObjCIsaExprClass: - case Expr::ShuffleVectorExprClass: - case Expr::BlockExprClass: - case Expr::BlockDeclRefExprClass: - case Expr::NoStmtClass: - return ICEDiag(2, E->getLocStart()); - - case Expr::GNUNullExprClass: - // GCC considers the GNU __null value to be an integral constant expression. - return NoDiag(); - - case Expr::ParenExprClass: - return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx); - case Expr::IntegerLiteralClass: - case Expr::CharacterLiteralClass: - case Expr::CXXBoolLiteralExprClass: - case Expr::CXXZeroInitValueExprClass: - case Expr::TypesCompatibleExprClass: - case Expr::UnaryTypeTraitExprClass: - return NoDiag(); - case Expr::CallExprClass: - case Expr::CXXOperatorCallExprClass: { - const CallExpr *CE = cast<CallExpr>(E); - if (CE->isBuiltinCall(Ctx)) - return CheckEvalInICE(E, Ctx); - return ICEDiag(2, E->getLocStart()); - } - case Expr::DeclRefExprClass: - if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) - return NoDiag(); - if (Ctx.getLangOptions().CPlusPlus && - E->getType().getCVRQualifiers() == Qualifiers::Const) { - const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); - - // Parameter variables are never constants. Without this check, - // getAnyInitializer() can find a default argument, which leads - // to chaos. - if (isa<ParmVarDecl>(D)) - return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); - - // C++ 7.1.5.1p2 - // A variable of non-volatile const-qualified integral or enumeration - // type initialized by an ICE can be used in ICEs. - if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) { - Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers(); - if (Quals.hasVolatile() || !Quals.hasConst()) - return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); - - // Look for a declaration of this variable that has an initializer. - const VarDecl *ID = 0; - const Expr *Init = Dcl->getAnyInitializer(ID); - if (Init) { - if (ID->isInitKnownICE()) { - // We have already checked whether this subexpression is an - // integral constant expression. - if (ID->isInitICE()) - return NoDiag(); - else - return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); - } - - // It's an ICE whether or not the definition we found is - // out-of-line. See DR 721 and the discussion in Clang PR - // 6206 for details. - - if (Dcl->isCheckingICE()) { - return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); - } - - Dcl->setCheckingICE(); - ICEDiag Result = CheckICE(Init, Ctx); - // Cache the result of the ICE test. - Dcl->setInitKnownICE(Result.Val == 0); - return Result; - } - } - } - return ICEDiag(2, E->getLocStart()); - case Expr::UnaryOperatorClass: { - const UnaryOperator *Exp = cast<UnaryOperator>(E); - switch (Exp->getOpcode()) { - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: - case UnaryOperator::AddrOf: - case UnaryOperator::Deref: - return ICEDiag(2, E->getLocStart()); - case UnaryOperator::Extension: - case UnaryOperator::LNot: - case UnaryOperator::Plus: - case UnaryOperator::Minus: - case UnaryOperator::Not: - case UnaryOperator::Real: - case UnaryOperator::Imag: - return CheckICE(Exp->getSubExpr(), Ctx); - case UnaryOperator::OffsetOf: - break; - } - - // OffsetOf falls through here. - } - case Expr::OffsetOfExprClass: { - // Note that per C99, offsetof must be an ICE. And AFAIK, using - // Evaluate matches the proposed gcc behavior for cases like - // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect - // compliance: we should warn earlier for offsetof expressions with - // array subscripts that aren't ICEs, and if the array subscripts - // are ICEs, the value of the offsetof must be an integer constant. - return CheckEvalInICE(E, Ctx); - } - case Expr::SizeOfAlignOfExprClass: { - const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E); - if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType()) - return ICEDiag(2, E->getLocStart()); - return NoDiag(); - } - case Expr::BinaryOperatorClass: { - const BinaryOperator *Exp = cast<BinaryOperator>(E); - switch (Exp->getOpcode()) { - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: - case BinaryOperator::Assign: - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: - case BinaryOperator::RemAssign: - case BinaryOperator::AddAssign: - case BinaryOperator::SubAssign: - case BinaryOperator::ShlAssign: - case BinaryOperator::ShrAssign: - case BinaryOperator::AndAssign: - case BinaryOperator::XorAssign: - case BinaryOperator::OrAssign: - return ICEDiag(2, E->getLocStart()); - - case BinaryOperator::Mul: - case BinaryOperator::Div: - case BinaryOperator::Rem: - case BinaryOperator::Add: - case BinaryOperator::Sub: - case BinaryOperator::Shl: - case BinaryOperator::Shr: - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: - case BinaryOperator::EQ: - case BinaryOperator::NE: - case BinaryOperator::And: - case BinaryOperator::Xor: - case BinaryOperator::Or: - case BinaryOperator::Comma: { - ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); - ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); - if (Exp->getOpcode() == BinaryOperator::Div || - Exp->getOpcode() == BinaryOperator::Rem) { - // Evaluate gives an error for undefined Div/Rem, so make sure - // we don't evaluate one. - if (LHSResult.Val != 2 && RHSResult.Val != 2) { - llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx); - if (REval == 0) - return ICEDiag(1, E->getLocStart()); - if (REval.isSigned() && REval.isAllOnesValue()) { - llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx); - if (LEval.isMinSignedValue()) - return ICEDiag(1, E->getLocStart()); - } - } - } - if (Exp->getOpcode() == BinaryOperator::Comma) { - if (Ctx.getLangOptions().C99) { - // C99 6.6p3 introduces a strange edge case: comma can be in an ICE - // if it isn't evaluated. - if (LHSResult.Val == 0 && RHSResult.Val == 0) - return ICEDiag(1, E->getLocStart()); - } else { - // In both C89 and C++, commas in ICEs are illegal. - return ICEDiag(2, E->getLocStart()); - } - } - if (LHSResult.Val >= RHSResult.Val) - return LHSResult; - return RHSResult; - } - case BinaryOperator::LAnd: - case BinaryOperator::LOr: { - ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); - ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); - if (LHSResult.Val == 0 && RHSResult.Val == 1) { - // Rare case where the RHS has a comma "side-effect"; we need - // to actually check the condition to see whether the side - // with the comma is evaluated. - if ((Exp->getOpcode() == BinaryOperator::LAnd) != - (Exp->getLHS()->EvaluateAsInt(Ctx) == 0)) - return RHSResult; - return NoDiag(); - } - - if (LHSResult.Val >= RHSResult.Val) - return LHSResult; - return RHSResult; - } - } - } - case Expr::ImplicitCastExprClass: - case Expr::CStyleCastExprClass: - case Expr::CXXFunctionalCastExprClass: - case Expr::CXXStaticCastExprClass: - case Expr::CXXReinterpretCastExprClass: - case Expr::CXXConstCastExprClass: { - const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr(); - if (SubExpr->getType()->isIntegralType()) - return CheckICE(SubExpr, Ctx); - if (isa<FloatingLiteral>(SubExpr->IgnoreParens())) - return NoDiag(); - return ICEDiag(2, E->getLocStart()); - } - case Expr::ConditionalOperatorClass: { - const ConditionalOperator *Exp = cast<ConditionalOperator>(E); - // If the condition (ignoring parens) is a __builtin_constant_p call, - // then only the true side is actually considered in an integer constant - // expression, and it is fully evaluated. This is an important GNU - // extension. See GCC PR38377 for discussion. - if (const CallExpr *CallCE - = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts())) - if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) { - Expr::EvalResult EVResult; - if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || - !EVResult.Val.isInt()) { - return ICEDiag(2, E->getLocStart()); - } - return NoDiag(); - } - ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx); - ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx); - ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); - if (CondResult.Val == 2) - return CondResult; - if (TrueResult.Val == 2) - return TrueResult; - if (FalseResult.Val == 2) - return FalseResult; - if (CondResult.Val == 1) - return CondResult; - if (TrueResult.Val == 0 && FalseResult.Val == 0) - return NoDiag(); - // Rare case where the diagnostics depend on which side is evaluated - // Note that if we get here, CondResult is 0, and at least one of - // TrueResult and FalseResult is non-zero. - if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) { - return FalseResult; - } - return TrueResult; - } - case Expr::CXXDefaultArgExprClass: - return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); - case Expr::ChooseExprClass: { - return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); - } - } - - // Silence a GCC warning - return ICEDiag(2, E->getLocStart()); -} - -bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, - SourceLocation *Loc, bool isEvaluated) const { - ICEDiag d = CheckICE(this, Ctx); - if (d.Val != 0) { - if (Loc) *Loc = d.Loc; - return false; - } - EvalResult EvalResult; - if (!Evaluate(EvalResult, Ctx)) - llvm_unreachable("ICE cannot be evaluated!"); - assert(!EvalResult.HasSideEffects && "ICE with side effects!"); - assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); - Result = EvalResult.Val.getInt(); - return true; -} - /// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an /// integer constant expression with the value zero, or if this is one that is /// cast to void*. @@ -2433,9 +2080,9 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { break; case Class: - if (const ObjCInterfaceType *Iface - = getClassReceiver()->getAs<ObjCInterfaceType>()) - return Iface->getDecl(); + if (const ObjCObjectType *Ty + = getClassReceiver()->getAs<ObjCObjectType>()) + return Ty->getInterface(); break; case SuperInstance: @@ -2712,7 +2359,9 @@ Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; } // ObjCImplicitSetterGetterRefExpr Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_begin() { - return &Base; + // If this is accessing a class member, skip that entry. + if (Base) return &Base; + return &Base+1; } Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_end() { return &Base+1; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 2e03beb0f050..d1a2b261f26b 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -92,12 +92,11 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, SourceLocation startLoc, SourceLocation endLoc) : Expr(CXXNewExprClass, ty, ty->isDependentType(), ty->isDependentType()), GlobalNew(globalNew), ParenTypeId(parenTypeId), - Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs), - NumConstructorArgs(numConsArgs), OperatorNew(operatorNew), + Initializer(initializer), SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete), Constructor(constructor), StartLoc(startLoc), EndLoc(endLoc) { - unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; - SubExprs = new (C) Stmt*[TotalSize]; + + AllocateArgsArray(C, arraySize != 0, numPlaceArgs, numConsArgs); unsigned i = 0; if (Array) SubExprs[i++] = arraySize; @@ -105,9 +104,20 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, SubExprs[i++] = placementArgs[j]; for (unsigned j = 0; j < NumConstructorArgs; ++j) SubExprs[i++] = constructorArgs[j]; - assert(i == TotalSize); } +void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, + unsigned numPlaceArgs, unsigned numConsArgs){ + assert(SubExprs == 0 && "SubExprs already allocated"); + Array = isArray; + NumPlacementArgs = numPlaceArgs; + NumConstructorArgs = numConsArgs; + + unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; + SubExprs = new (C) Stmt*[TotalSize]; +} + + void CXXNewExpr::DoDestroy(ASTContext &C) { DestroyChildren(C); if (SubExprs) @@ -134,7 +144,7 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info) : Type(Info) { - Location = Info->getTypeLoc().getSourceRange().getBegin(); + Location = Info->getTypeLoc().getLocalSourceRange().getBegin(); } QualType CXXPseudoDestructorExpr::getDestroyedType() const { @@ -147,7 +157,7 @@ QualType CXXPseudoDestructorExpr::getDestroyedType() const { SourceRange CXXPseudoDestructorExpr::getSourceRange() const { SourceLocation End = DestroyedType.getLocation(); if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) - End = TInfo->getTypeLoc().getSourceRange().getEnd(); + End = TInfo->getTypeLoc().getLocalSourceRange().getEnd(); return SourceRange(Base->getLocStart(), End); } @@ -159,23 +169,47 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, DeclarationName Name, SourceLocation NameLoc, bool ADL, - const TemplateArgumentListInfo &Args) + const TemplateArgumentListInfo &Args, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) { void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) + ExplicitTemplateArgumentList::sizeFor(Args)); UnresolvedLookupExpr *ULE - = new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, + = new (Mem) UnresolvedLookupExpr(C, + Dependent ? C.DependentTy : C.OverloadTy, Dependent, NamingClass, Qualifier, QualifierRange, Name, NameLoc, ADL, /*Overload*/ true, - /*ExplicitTemplateArgs*/ true); + /*ExplicitTemplateArgs*/ true, + Begin, End); reinterpret_cast<ExplicitTemplateArgumentList*>(ULE+1)->initializeFrom(Args); return ULE; } +OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, QualType T, + bool Dependent, NestedNameSpecifier *Qualifier, + SourceRange QRange, DeclarationName Name, + SourceLocation NameLoc, bool HasTemplateArgs, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) + : Expr(K, T, Dependent, Dependent), + Results(0), NumResults(End - Begin), Name(Name), Qualifier(Qualifier), + QualifierRange(QRange), NameLoc(NameLoc), + HasExplicitTemplateArgs(HasTemplateArgs) +{ + if (NumResults) { + Results = static_cast<DeclAccessPair *>( + C.Allocate(sizeof(DeclAccessPair) * NumResults, + llvm::alignof<DeclAccessPair>())); + memcpy(Results, &*Begin.getIterator(), + (End - Begin) * sizeof(DeclAccessPair)); + } +} + bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin, UnresolvedSetIterator End, const TemplateArgumentListInfo *Args) { @@ -517,35 +551,43 @@ void CXXConstructExpr::DoDestroy(ASTContext &C) { C.Deallocate(this); } -CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, +CXXExprWithTemporaries::CXXExprWithTemporaries(ASTContext &C, + Expr *subexpr, CXXTemporary **temps, unsigned numtemps) -: Expr(CXXExprWithTemporariesClass, subexpr->getType(), + : Expr(CXXExprWithTemporariesClass, subexpr->getType(), subexpr->isTypeDependent(), subexpr->isValueDependent()), - SubExpr(subexpr), Temps(0), NumTemps(numtemps) { - if (NumTemps > 0) { - Temps = new CXXTemporary*[NumTemps]; - for (unsigned i = 0; i < NumTemps; ++i) + SubExpr(subexpr), Temps(0), NumTemps(0) { + if (numtemps) { + setNumTemporaries(C, numtemps); + for (unsigned i = 0; i != numtemps; ++i) Temps[i] = temps[i]; } } +void CXXExprWithTemporaries::setNumTemporaries(ASTContext &C, unsigned N) { + assert(Temps == 0 && "Cannot resize with this"); + NumTemps = N; + Temps = new (C) CXXTemporary*[NumTemps]; +} + + CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, unsigned NumTemps) { - return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps); + return new (C) CXXExprWithTemporaries(C, SubExpr, Temps, NumTemps); } void CXXExprWithTemporaries::DoDestroy(ASTContext &C) { DestroyChildren(C); + if (Temps) + C.Deallocate(Temps); this->~CXXExprWithTemporaries(); C.Deallocate(this); } -CXXExprWithTemporaries::~CXXExprWithTemporaries() { - delete[] Temps; -} +CXXExprWithTemporaries::~CXXExprWithTemporaries() {} // CXXBindTemporaryExpr Stmt::child_iterator CXXBindTemporaryExpr::child_begin() { @@ -682,7 +724,8 @@ Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() { return child_iterator(&Base + 1); } -UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, +UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, QualType T, + bool Dependent, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, @@ -691,10 +734,12 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, SourceRange QualifierRange, DeclarationName MemberName, SourceLocation MemberLoc, - const TemplateArgumentListInfo *TemplateArgs) - : OverloadExpr(UnresolvedMemberExprClass, T, Dependent, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) + : OverloadExpr(UnresolvedMemberExprClass, C, T, Dependent, Qualifier, QualifierRange, MemberName, MemberLoc, - TemplateArgs != 0), + TemplateArgs != 0, Begin, End), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { if (TemplateArgs) @@ -710,17 +755,19 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, SourceRange QualifierRange, DeclarationName Member, SourceLocation MemberLoc, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) { std::size_t size = sizeof(UnresolvedMemberExpr); if (TemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>()); - return new (Mem) UnresolvedMemberExpr( + return new (Mem) UnresolvedMemberExpr(C, Dependent ? C.DependentTy : C.OverloadTy, Dependent, HasUnresolvedUsing, Base, BaseType, IsArrow, OperatorLoc, Qualifier, QualifierRange, - Member, MemberLoc, TemplateArgs); + Member, MemberLoc, TemplateArgs, Begin, End); } CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index c1a42d88fffa..dc614018ec2b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -48,31 +48,110 @@ struct EvalInfo { /// EvalResult - Contains information about the evaluation. Expr::EvalResult &EvalResult; - /// AnyLValue - Stack based LValue results are not discarded. - bool AnyLValue; - - EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult, - bool anylvalue = false) - : Ctx(ctx), EvalResult(evalresult), AnyLValue(anylvalue) {} + EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult) + : Ctx(ctx), EvalResult(evalresult) {} }; +namespace { + struct ComplexValue { + private: + bool IsInt; -static bool EvaluateLValue(const Expr *E, APValue &Result, EvalInfo &Info); -static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info); + public: + APSInt IntReal, IntImag; + APFloat FloatReal, FloatImag; + + ComplexValue() : FloatReal(APFloat::Bogus), FloatImag(APFloat::Bogus) {} + + void makeComplexFloat() { IsInt = false; } + bool isComplexFloat() const { return !IsInt; } + APFloat &getComplexFloatReal() { return FloatReal; } + APFloat &getComplexFloatImag() { return FloatImag; } + + void makeComplexInt() { IsInt = true; } + bool isComplexInt() const { return IsInt; } + APSInt &getComplexIntReal() { return IntReal; } + APSInt &getComplexIntImag() { return IntImag; } + + void moveInto(APValue &v) { + if (isComplexFloat()) + v = APValue(FloatReal, FloatImag); + else + v = APValue(IntReal, IntImag); + } + }; + + struct LValue { + Expr *Base; + CharUnits Offset; + + Expr *getLValueBase() { return Base; } + CharUnits getLValueOffset() { return Offset; } + + void moveInto(APValue &v) { + v = APValue(Base, Offset); + } + }; +} + +static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); +static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); -static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info); +static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); //===----------------------------------------------------------------------===// // Misc utilities //===----------------------------------------------------------------------===// -static bool EvalPointerValueAsBool(APValue& Value, bool& Result) { - // FIXME: Is this accurate for all kinds of bases? If not, what would - // the check look like? - Result = Value.getLValueBase() || !Value.getLValueOffset().isZero(); +static bool IsGlobalLValue(const Expr* E) { + if (!E) return true; + + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (isa<FunctionDecl>(DRE->getDecl())) + return true; + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) + return VD->hasGlobalStorage(); + return false; + } + + if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(E)) + return CLE->isFileScope(); + + return true; +} + +static bool EvalPointerValueAsBool(LValue& Value, bool& Result) { + const Expr* Base = Value.Base; + + // A null base expression indicates a null pointer. These are always + // evaluatable, and they are false unless the offset is zero. + if (!Base) { + Result = !Value.Offset.isZero(); + return true; + } + + // Require the base expression to be a global l-value. + if (!IsGlobalLValue(Base)) return false; + + // We have a non-null base expression. These are generally known to + // be true, but if it'a decl-ref to a weak symbol it can be null at + // runtime. + Result = true; + + const DeclRefExpr* DeclRef = dyn_cast<DeclRefExpr>(Base); + if (!DeclRef) + return true; + + // If it's a weak symbol, it isn't constant-evaluable. + const ValueDecl* Decl = DeclRef->getDecl(); + if (Decl->hasAttr<WeakAttr>() || + Decl->hasAttr<WeakRefAttr>() || + Decl->hasAttr<WeakImportAttr>()) + return false; + return true; } @@ -91,12 +170,12 @@ static bool HandleConversionToBool(const Expr* E, bool& Result, Result = !FloatResult.isZero(); return true; } else if (E->getType()->hasPointerRepresentation()) { - APValue PointerResult; + LValue PointerResult; if (!EvaluatePointer(E, PointerResult, Info)) return false; return EvalPointerValueAsBool(PointerResult, Result); } else if (E->getType()->isAnyComplexType()) { - APValue ComplexResult; + ComplexValue ComplexResult; if (!EvaluateComplex(E, ComplexResult, Info)) return false; if (ComplexResult.isComplexFloat()) { @@ -221,34 +300,42 @@ public: //===----------------------------------------------------------------------===// namespace { class LValueExprEvaluator - : public StmtVisitor<LValueExprEvaluator, APValue> { + : public StmtVisitor<LValueExprEvaluator, bool> { EvalInfo &Info; + LValue &Result; + + bool Success(Expr *E) { + Result.Base = E; + Result.Offset = CharUnits::Zero(); + return true; + } public: - LValueExprEvaluator(EvalInfo &info) : Info(info) {} + LValueExprEvaluator(EvalInfo &info, LValue &Result) : + Info(info), Result(Result) {} - APValue VisitStmt(Stmt *S) { - return APValue(); + bool VisitStmt(Stmt *S) { + return false; } - APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - APValue VisitDeclRefExpr(DeclRefExpr *E); - APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); } - APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E); - APValue VisitMemberExpr(MemberExpr *E); - APValue VisitStringLiteral(StringLiteral *E) { return APValue(E); } - APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E); } - APValue VisitArraySubscriptExpr(ArraySubscriptExpr *E); - APValue VisitUnaryDeref(UnaryOperator *E); - APValue VisitUnaryExtension(const UnaryOperator *E) + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitDeclRefExpr(DeclRefExpr *E); + bool VisitPredefinedExpr(PredefinedExpr *E) { return Success(E); } + bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E); + bool VisitMemberExpr(MemberExpr *E); + bool VisitStringLiteral(StringLiteral *E) { return Success(E); } + bool VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return Success(E); } + bool VisitArraySubscriptExpr(ArraySubscriptExpr *E); + bool VisitUnaryDeref(UnaryOperator *E); + bool VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } - APValue VisitChooseExpr(const ChooseExpr *E) + bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } - APValue VisitCastExpr(CastExpr *E) { + bool VisitCastExpr(CastExpr *E) { switch (E->getCastKind()) { default: - return APValue(); + return false; case CastExpr::CK_NoOp: return Visit(E->getSubExpr()); @@ -258,44 +345,41 @@ public: }; } // end anonymous namespace -static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) { - Result = LValueExprEvaluator(Info).Visit(const_cast<Expr*>(E)); - return Result.isLValue(); +static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) { + return LValueExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); } -APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { +bool LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { if (isa<FunctionDecl>(E->getDecl())) { - return APValue(E); + return Success(E); } else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) { - if (!Info.AnyLValue && !VD->hasGlobalStorage()) - return APValue(); if (!VD->getType()->isReferenceType()) - return APValue(E); + return Success(E); + // Reference parameters can refer to anything even if they have an + // "initializer" in the form of a default argument. + if (isa<ParmVarDecl>(VD)) + return false; // FIXME: Check whether VD might be overridden! if (const Expr *Init = VD->getAnyInitializer()) return Visit(const_cast<Expr *>(Init)); } - return APValue(); + return false; } -APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - if (!Info.AnyLValue && !E->isFileScope()) - return APValue(); - return APValue(E); +bool LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + return Success(E); } -APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { - APValue result; +bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { QualType Ty; if (E->isArrow()) { - if (!EvaluatePointer(E->getBase(), result, Info)) - return APValue(); + if (!EvaluatePointer(E->getBase(), Result, Info)) + return false; Ty = E->getBase()->getType()->getAs<PointerType>()->getPointeeType(); } else { - result = Visit(E->getBase()); - if (result.isUninit()) - return APValue(); + if (!Visit(E->getBase())) + return false; Ty = E->getBase()->getType(); } @@ -304,10 +388,10 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); if (!FD) // FIXME: deal with other kinds of member expressions - return APValue(); + return false; if (FD->getType()->isReferenceType()) - return APValue(); + return false; // FIXME: This is linear time. unsigned i = 0; @@ -318,36 +402,25 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { break; } - result.setLValue(result.getLValueBase(), - result.getLValueOffset() + - CharUnits::fromQuantity(RL.getFieldOffset(i) / 8)); - - return result; + Result.Offset += CharUnits::fromQuantity(RL.getFieldOffset(i) / 8); + return true; } -APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { - APValue Result; - +bool LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { if (!EvaluatePointer(E->getBase(), Result, Info)) - return APValue(); + return false; APSInt Index; if (!EvaluateInteger(E->getIdx(), Index, Info)) - return APValue(); + return false; CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(E->getType()); - - CharUnits Offset = Index.getSExtValue() * ElementSize; - Result.setLValue(Result.getLValueBase(), - Result.getLValueOffset() + Offset); - return Result; + Result.Offset += Index.getSExtValue() * ElementSize; + return true; } -APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) { - APValue Result; - if (!EvaluatePointer(E->getSubExpr(), Result, Info)) - return APValue(); - return Result; +bool LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) { + return EvaluatePointer(E->getSubExpr(), Result, Info); } //===----------------------------------------------------------------------===// @@ -356,104 +429,103 @@ APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) { namespace { class PointerExprEvaluator - : public StmtVisitor<PointerExprEvaluator, APValue> { + : public StmtVisitor<PointerExprEvaluator, bool> { EvalInfo &Info; + LValue &Result; + + bool Success(Expr *E) { + Result.Base = E; + Result.Offset = CharUnits::Zero(); + return true; + } public: - PointerExprEvaluator(EvalInfo &info) : Info(info) {} + PointerExprEvaluator(EvalInfo &info, LValue &Result) + : Info(info), Result(Result) {} - APValue VisitStmt(Stmt *S) { - return APValue(); + bool VisitStmt(Stmt *S) { + return false; } - APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - APValue VisitBinaryOperator(const BinaryOperator *E); - APValue VisitCastExpr(CastExpr* E); - APValue VisitUnaryExtension(const UnaryOperator *E) + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitCastExpr(CastExpr* E); + bool VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } - APValue VisitUnaryAddrOf(const UnaryOperator *E); - APValue VisitObjCStringLiteral(ObjCStringLiteral *E) - { return APValue(E); } - APValue VisitAddrLabelExpr(AddrLabelExpr *E) - { return APValue(E); } - APValue VisitCallExpr(CallExpr *E); - APValue VisitBlockExpr(BlockExpr *E) { + bool VisitUnaryAddrOf(const UnaryOperator *E); + bool VisitObjCStringLiteral(ObjCStringLiteral *E) + { return Success(E); } + bool VisitAddrLabelExpr(AddrLabelExpr *E) + { return Success(E); } + bool VisitCallExpr(CallExpr *E); + bool VisitBlockExpr(BlockExpr *E) { if (!E->hasBlockDeclRefExprs()) - return APValue(E); - return APValue(); + return Success(E); + return false; } - APValue VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) - { return APValue((Expr*)0); } - APValue VisitConditionalOperator(ConditionalOperator *E); - APValue VisitChooseExpr(ChooseExpr *E) + bool VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) + { return Success((Expr*)0); } + bool VisitConditionalOperator(ConditionalOperator *E); + bool VisitChooseExpr(ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } - APValue VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) - { return APValue((Expr*)0); } + bool VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) + { return Success((Expr*)0); } // FIXME: Missing: @protocol, @selector }; } // end anonymous namespace -static bool EvaluatePointer(const Expr* E, APValue& Result, EvalInfo &Info) { - if (!E->getType()->hasPointerRepresentation()) - return false; - Result = PointerExprEvaluator(Info).Visit(const_cast<Expr*>(E)); - return Result.isLValue(); +static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) { + assert(E->getType()->hasPointerRepresentation()); + return PointerExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); } -APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { +bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->getOpcode() != BinaryOperator::Add && E->getOpcode() != BinaryOperator::Sub) - return APValue(); + return false; const Expr *PExp = E->getLHS(); const Expr *IExp = E->getRHS(); if (IExp->getType()->isPointerType()) std::swap(PExp, IExp); - APValue ResultLValue; - if (!EvaluatePointer(PExp, ResultLValue, Info)) - return APValue(); + if (!EvaluatePointer(PExp, Result, Info)) + return false; - llvm::APSInt AdditionalOffset; - if (!EvaluateInteger(IExp, AdditionalOffset, Info)) - return APValue(); + llvm::APSInt Offset; + if (!EvaluateInteger(IExp, Offset, Info)) + return false; + int64_t AdditionalOffset + = Offset.isSigned() ? Offset.getSExtValue() + : static_cast<int64_t>(Offset.getZExtValue()); // Compute the new offset in the appropriate width. QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType(); - llvm::APSInt SizeOfPointee(AdditionalOffset); + CharUnits SizeOfPointee; // Explicitly handle GNU void* and function pointer arithmetic extensions. if (PointeeType->isVoidType() || PointeeType->isFunctionType()) - SizeOfPointee = 1; + SizeOfPointee = CharUnits::One(); else - SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType).getQuantity(); + SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType); - llvm::APSInt Offset(AdditionalOffset); - Offset = ResultLValue.getLValueOffset().getQuantity(); if (E->getOpcode() == BinaryOperator::Add) - Offset += AdditionalOffset * SizeOfPointee; + Result.Offset += AdditionalOffset * SizeOfPointee; else - Offset -= AdditionalOffset * SizeOfPointee; + Result.Offset -= AdditionalOffset * SizeOfPointee; - // Sign extend prior to converting back to a char unit. - if (Offset.getBitWidth() < 64) - Offset.extend(64); - return APValue(ResultLValue.getLValueBase(), - CharUnits::fromQuantity(Offset.getLimitedValue())); + return true; } -APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { - APValue result; - if (EvaluateLValue(E->getSubExpr(), result, Info)) - return result; - return APValue(); +bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { + return EvaluateLValue(E->getSubExpr(), Result, Info); } -APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) { +bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { Expr* SubExpr = E->getSubExpr(); switch (E->getCastKind()) { @@ -471,18 +543,20 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) { return Visit(SubExpr); if (SubExpr->getType()->isIntegralType()) { - APValue Result; - if (!EvaluateIntegerOrLValue(SubExpr, Result, Info)) + APValue Value; + if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) break; - if (Result.isInt()) { - Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); - return APValue(0, - CharUnits::fromQuantity(Result.getInt().getZExtValue())); + if (Value.isInt()) { + Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); + Result.Base = 0; + Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue()); + return true; + } else { + Result.Base = Value.getLValueBase(); + Result.Offset = Value.getLValueOffset(); + return true; } - - // Cast is of an lvalue, no need to change value. - return Result; } break; } @@ -494,51 +568,46 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) { return Visit(SubExpr); case CastExpr::CK_IntegralToPointer: { - APValue Result; - if (!EvaluateIntegerOrLValue(SubExpr, Result, Info)) + APValue Value; + if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) break; - if (Result.isInt()) { - Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); - return APValue(0, - CharUnits::fromQuantity(Result.getInt().getZExtValue())); + if (Value.isInt()) { + Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); + Result.Base = 0; + Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue()); + return true; + } else { + // Cast is of an lvalue, no need to change value. + Result.Base = Value.getLValueBase(); + Result.Offset = Value.getLValueOffset(); + return true; } - - // Cast is of an lvalue, no need to change value. - return Result; } case CastExpr::CK_ArrayToPointerDecay: - case CastExpr::CK_FunctionToPointerDecay: { - APValue Result; - if (EvaluateLValue(SubExpr, Result, Info)) - return Result; - break; - } + case CastExpr::CK_FunctionToPointerDecay: + return EvaluateLValue(SubExpr, Result, Info); } - return APValue(); + return false; } -APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) { +bool PointerExprEvaluator::VisitCallExpr(CallExpr *E) { if (E->isBuiltinCall(Info.Ctx) == Builtin::BI__builtin___CFStringMakeConstantString || E->isBuiltinCall(Info.Ctx) == Builtin::BI__builtin___NSStringMakeConstantString) - return APValue(E); - return APValue(); + return Success(E); + return false; } -APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { +bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { bool BoolResult; if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) - return APValue(); + return false; Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); - - APValue Result; - if (EvaluatePointer(EvalExpr, Result, Info)) - return Result; - return APValue(); + return Visit(EvalExpr); } //===----------------------------------------------------------------------===// @@ -867,18 +936,20 @@ public: private: CharUnits GetAlignOfExpr(const Expr *E); CharUnits GetAlignOfType(QualType T); + static QualType GetObjectType(const Expr *E); + bool TryEvaluateBuiltinObjectSize(CallExpr *E); // FIXME: Missing: array subscript of vector, member of vector }; } // end anonymous namespace static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) { - if (!E->getType()->isIntegralType()) - return false; - + assert(E->getType()->isIntegralType()); return IntExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); } static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { + assert(E->getType()->isIntegralType()); + APValue Val; if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt()) return false; @@ -984,36 +1055,55 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { return -1; } +/// Retrieves the "underlying object type" of the given expression, +/// as used by __builtin_object_size. +QualType IntExprEvaluator::GetObjectType(const Expr *E) { + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) + return VD->getType(); + } else if (isa<CompoundLiteralExpr>(E)) { + return E->getType(); + } + + return QualType(); +} + +bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) { + // TODO: Perhaps we should let LLVM lower this? + LValue Base; + if (!EvaluatePointer(E->getArg(0), Base, Info)) + return false; + + // If we can prove the base is null, lower to zero now. + const Expr *LVBase = Base.getLValueBase(); + if (!LVBase) return Success(0, E); + + QualType T = GetObjectType(LVBase); + if (T.isNull() || + T->isIncompleteType() || + !T->isObjectType() || + T->isVariablyModifiedType() || + T->isDependentType()) + return false; + + CharUnits Size = Info.Ctx.getTypeSizeInChars(T); + CharUnits Offset = Base.getLValueOffset(); + + if (!Offset.isNegative() && Offset <= Size) + Size -= Offset; + else + Size = CharUnits::Zero(); + return Success(Size.getQuantity(), E); +} + bool IntExprEvaluator::VisitCallExpr(CallExpr *E) { switch (E->isBuiltinCall(Info.Ctx)) { default: return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); case Builtin::BI__builtin_object_size: { - const Expr *Arg = E->getArg(0)->IgnoreParens(); - Expr::EvalResult Base; - - // TODO: Perhaps we should let LLVM lower this? - if (Arg->EvaluateAsAny(Base, Info.Ctx) - && Base.Val.getKind() == APValue::LValue - && !Base.HasSideEffects) - if (const Expr *LVBase = Base.Val.getLValueBase()) - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LVBase)) { - if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { - if (!VD->getType()->isIncompleteType() - && VD->getType()->isObjectType() - && !VD->getType()->isVariablyModifiedType() - && !VD->getType()->isDependentType()) { - CharUnits Size = Info.Ctx.getTypeSizeInChars(VD->getType()); - CharUnits Offset = Base.Val.getLValueOffset(); - if (!Offset.isNegative() && Offset <= Size) - Size -= Offset; - else - Size = CharUnits::Zero(); - return Success(Size.getQuantity(), E); - } - } - } + if (TryEvaluateBuiltinObjectSize(E)) + return true; // If evaluating the argument has side-effects we can't determine // the size of the object and lower it to unknown now. @@ -1098,7 +1188,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (LHSTy->isAnyComplexType()) { assert(RHSTy->isAnyComplexType() && "Invalid comparison"); - APValue LHS, RHS; + ComplexValue LHS, RHS; if (!EvaluateComplex(E->getLHS(), LHS, Info)) return false; @@ -1173,11 +1263,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (LHSTy->isPointerType() && RHSTy->isPointerType()) { if (E->getOpcode() == BinaryOperator::Sub || E->isEqualityOp()) { - APValue LHSValue; + LValue LHSValue; if (!EvaluatePointer(E->getLHS(), LHSValue, Info)) return false; - APValue RHSValue; + LValue RHSValue; if (!EvaluatePointer(E->getRHS(), RHSValue, Info)) return false; @@ -1463,7 +1553,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { if (E->isOffsetOfOp()) { // The AST for offsetof is defined in such a way that we can just // directly Evaluate it as an l-value. - APValue LV; + LValue LV; if (!EvaluateLValue(E->getSubExpr(), LV, Info)) return false; if (LV.getLValueBase()) @@ -1538,7 +1628,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { // FIXME: Clean this up! if (SrcType->isPointerType()) { - APValue LV; + LValue LV; if (!EvaluatePointer(SubExpr, LV, Info)) return false; @@ -1547,7 +1637,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(SrcType)) return false; - Result = LV; + LV.moveInto(Result); return true; } @@ -1559,19 +1649,19 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { if (SrcType->isArrayType() || SrcType->isFunctionType()) { // This handles double-conversion cases, where there's both // an l-value promotion and an implicit conversion to int. - APValue LV; + LValue LV; if (!EvaluateLValue(SubExpr, LV, Info)) return false; if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(Info.Ctx.VoidPtrTy)) return false; - Result = LV; + LV.moveInto(Result); return true; } if (SrcType->isAnyComplexType()) { - APValue C; + ComplexValue C; if (!EvaluateComplex(SubExpr, C, Info)) return false; if (C.isComplexFloat()) @@ -1596,7 +1686,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { if (E->getSubExpr()->getType()->isAnyComplexType()) { - APValue LV; + ComplexValue LV; if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt()) return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); return Success(LV.getComplexIntReal(), E); @@ -1607,7 +1697,7 @@ bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { if (E->getSubExpr()->getType()->isComplexIntegerType()) { - APValue LV; + ComplexValue LV; if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt()) return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); return Success(LV.getComplexIntImag(), E); @@ -1649,13 +1739,16 @@ public: { return Visit(E->getChosenSubExpr(Info.Ctx)); } bool VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } + bool VisitUnaryReal(const UnaryOperator *E); + bool VisitUnaryImag(const UnaryOperator *E); - // FIXME: Missing: __real__/__imag__, array subscript of vector, - // member of vector, ImplicitValueInitExpr + // FIXME: Missing: array subscript of vector, member of vector, + // ImplicitValueInitExpr }; } // end anonymous namespace static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) { + assert(E->getType()->isRealFloatingType()); return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); } @@ -1736,6 +1829,22 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { } } +bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { + ComplexValue CV; + if (!EvaluateComplex(E->getSubExpr(), CV, Info)) + return false; + Result = CV.FloatReal; + return true; +} + +bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { + ComplexValue CV; + if (!EvaluateComplex(E->getSubExpr(), CV, Info)) + return false; + Result = CV.FloatImag; + return true; +} + bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { if (E->getOpcode() == UnaryOperator::Deref) return false; @@ -1838,166 +1947,170 @@ bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { namespace { class ComplexExprEvaluator - : public StmtVisitor<ComplexExprEvaluator, APValue> { + : public StmtVisitor<ComplexExprEvaluator, bool> { EvalInfo &Info; + ComplexValue &Result; public: - ComplexExprEvaluator(EvalInfo &info) : Info(info) {} + ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result) + : Info(info), Result(Result) {} //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// - APValue VisitStmt(Stmt *S) { - return APValue(); + bool VisitStmt(Stmt *S) { + return false; } - APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - APValue VisitImaginaryLiteral(ImaginaryLiteral *E) { + bool VisitImaginaryLiteral(ImaginaryLiteral *E) { Expr* SubExpr = E->getSubExpr(); if (SubExpr->getType()->isRealFloatingType()) { - APFloat Result(0.0); - - if (!EvaluateFloat(SubExpr, Result, Info)) - return APValue(); + Result.makeComplexFloat(); + APFloat &Imag = Result.FloatImag; + if (!EvaluateFloat(SubExpr, Imag, Info)) + return false; - return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false), - Result); + Result.FloatReal = APFloat(Imag.getSemantics()); + return true; } else { assert(SubExpr->getType()->isIntegerType() && "Unexpected imaginary literal."); - llvm::APSInt Result; - if (!EvaluateInteger(SubExpr, Result, Info)) - return APValue(); + Result.makeComplexInt(); + APSInt &Imag = Result.IntImag; + if (!EvaluateInteger(SubExpr, Imag, Info)) + return false; - llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned()); - Zero = 0; - return APValue(Zero, Result); + Result.IntReal = APSInt(Imag.getBitWidth(), !Imag.isSigned()); + return true; } } - APValue VisitCastExpr(CastExpr *E) { + bool VisitCastExpr(CastExpr *E) { Expr* SubExpr = E->getSubExpr(); QualType EltType = E->getType()->getAs<ComplexType>()->getElementType(); QualType SubType = SubExpr->getType(); if (SubType->isRealFloatingType()) { - APFloat Result(0.0); - - if (!EvaluateFloat(SubExpr, Result, Info)) - return APValue(); + APFloat &Real = Result.FloatReal; + if (!EvaluateFloat(SubExpr, Real, Info)) + return false; if (EltType->isRealFloatingType()) { - Result = HandleFloatToFloatCast(EltType, SubType, Result, Info.Ctx); - return APValue(Result, - APFloat(Result.getSemantics(), APFloat::fcZero, false)); + Result.makeComplexFloat(); + Real = HandleFloatToFloatCast(EltType, SubType, Real, Info.Ctx); + Result.FloatImag = APFloat(Real.getSemantics()); + return true; } else { - llvm::APSInt IResult; - IResult = HandleFloatToIntCast(EltType, SubType, Result, Info.Ctx); - llvm::APSInt Zero(IResult.getBitWidth(), !IResult.isSigned()); - Zero = 0; - return APValue(IResult, Zero); + Result.makeComplexInt(); + Result.IntReal = HandleFloatToIntCast(EltType, SubType, Real, Info.Ctx); + Result.IntImag = APSInt(Result.IntReal.getBitWidth(), + !Result.IntReal.isSigned()); + return true; } } else if (SubType->isIntegerType()) { - APSInt Result; - - if (!EvaluateInteger(SubExpr, Result, Info)) - return APValue(); + APSInt &Real = Result.IntReal; + if (!EvaluateInteger(SubExpr, Real, Info)) + return false; if (EltType->isRealFloatingType()) { - APFloat FResult = - HandleIntToFloatCast(EltType, SubType, Result, Info.Ctx); - return APValue(FResult, - APFloat(FResult.getSemantics(), APFloat::fcZero, false)); + Result.makeComplexFloat(); + Result.FloatReal + = HandleIntToFloatCast(EltType, SubType, Real, Info.Ctx); + Result.FloatImag = APFloat(Result.FloatReal.getSemantics()); + return true; } else { - Result = HandleIntToIntCast(EltType, SubType, Result, Info.Ctx); - llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned()); - Zero = 0; - return APValue(Result, Zero); + Result.makeComplexInt(); + Real = HandleIntToIntCast(EltType, SubType, Real, Info.Ctx); + Result.IntImag = APSInt(Real.getBitWidth(), !Real.isSigned()); + return true; } } else if (const ComplexType *CT = SubType->getAs<ComplexType>()) { - APValue Src; - - if (!EvaluateComplex(SubExpr, Src, Info)) - return APValue(); + if (!Visit(SubExpr)) + return false; QualType SrcType = CT->getElementType(); - if (Src.isComplexFloat()) { + if (Result.isComplexFloat()) { if (EltType->isRealFloatingType()) { - return APValue(HandleFloatToFloatCast(EltType, SrcType, - Src.getComplexFloatReal(), - Info.Ctx), - HandleFloatToFloatCast(EltType, SrcType, - Src.getComplexFloatImag(), - Info.Ctx)); + Result.makeComplexFloat(); + Result.FloatReal = HandleFloatToFloatCast(EltType, SrcType, + Result.FloatReal, + Info.Ctx); + Result.FloatImag = HandleFloatToFloatCast(EltType, SrcType, + Result.FloatImag, + Info.Ctx); + return true; } else { - return APValue(HandleFloatToIntCast(EltType, SrcType, - Src.getComplexFloatReal(), - Info.Ctx), - HandleFloatToIntCast(EltType, SrcType, - Src.getComplexFloatImag(), - Info.Ctx)); + Result.makeComplexInt(); + Result.IntReal = HandleFloatToIntCast(EltType, SrcType, + Result.FloatReal, + Info.Ctx); + Result.IntImag = HandleFloatToIntCast(EltType, SrcType, + Result.FloatImag, + Info.Ctx); + return true; } } else { - assert(Src.isComplexInt() && "Invalid evaluate result."); + assert(Result.isComplexInt() && "Invalid evaluate result."); if (EltType->isRealFloatingType()) { - return APValue(HandleIntToFloatCast(EltType, SrcType, - Src.getComplexIntReal(), - Info.Ctx), - HandleIntToFloatCast(EltType, SrcType, - Src.getComplexIntImag(), - Info.Ctx)); + Result.makeComplexFloat(); + Result.FloatReal = HandleIntToFloatCast(EltType, SrcType, + Result.IntReal, + Info.Ctx); + Result.FloatImag = HandleIntToFloatCast(EltType, SrcType, + Result.IntImag, + Info.Ctx); + return true; } else { - return APValue(HandleIntToIntCast(EltType, SrcType, - Src.getComplexIntReal(), - Info.Ctx), - HandleIntToIntCast(EltType, SrcType, - Src.getComplexIntImag(), - Info.Ctx)); + Result.makeComplexInt(); + Result.IntReal = HandleIntToIntCast(EltType, SrcType, + Result.IntReal, + Info.Ctx); + Result.IntImag = HandleIntToIntCast(EltType, SrcType, + Result.IntImag, + Info.Ctx); + return true; } } } // FIXME: Handle more casts. - return APValue(); + return false; } - APValue VisitBinaryOperator(const BinaryOperator *E); - APValue VisitChooseExpr(const ChooseExpr *E) + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } - APValue VisitUnaryExtension(const UnaryOperator *E) + bool VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } // FIXME Missing: unary +/-/~, binary div, ImplicitValueInitExpr, // conditional ?:, comma }; } // end anonymous namespace -static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info) { - Result = ComplexExprEvaluator(Info).Visit(const_cast<Expr*>(E)); - assert((!Result.isComplexFloat() || - (&Result.getComplexFloatReal().getSemantics() == - &Result.getComplexFloatImag().getSemantics())) && - "Invalid complex evaluation."); - return Result.isComplexFloat() || Result.isComplexInt(); +static bool EvaluateComplex(const Expr *E, ComplexValue &Result, + EvalInfo &Info) { + assert(E->getType()->isAnyComplexType()); + return ComplexExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); } -APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { - APValue Result, RHS; - - if (!EvaluateComplex(E->getLHS(), Result, Info)) - return APValue(); +bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (!Visit(E->getLHS())) + return false; + ComplexValue RHS; if (!EvaluateComplex(E->getRHS(), RHS, Info)) - return APValue(); + return false; assert(Result.isComplexFloat() == RHS.isComplexFloat() && "Invalid operands to binary operator."); switch (E->getOpcode()) { - default: return APValue(); + default: return false; case BinaryOperator::Add: if (Result.isComplexFloat()) { Result.getComplexFloatReal().add(RHS.getComplexFloatReal(), @@ -2022,7 +2135,7 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { break; case BinaryOperator::Mul: if (Result.isComplexFloat()) { - APValue LHS = Result; + ComplexValue LHS = Result; APFloat &LHS_r = LHS.getComplexFloatReal(); APFloat &LHS_i = LHS.getComplexFloatImag(); APFloat &RHS_r = RHS.getComplexFloatReal(); @@ -2042,7 +2155,7 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven); Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven); } else { - APValue LHS = Result; + ComplexValue LHS = Result; Result.getComplexIntReal() = (LHS.getComplexIntReal() * RHS.getComplexIntReal() - LHS.getComplexIntImag() * RHS.getComplexIntImag()); @@ -2053,7 +2166,7 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { break; } - return Result; + return true; } //===----------------------------------------------------------------------===// @@ -2065,53 +2178,32 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { /// we want to. If this function returns true, it returns the folded constant /// in Result. bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const { + const Expr *E = this; EvalInfo Info(Ctx, Result); - - if (getType()->isVectorType()) { - if (!EvaluateVector(this, Result.Val, Info)) + if (E->getType()->isVectorType()) { + if (!EvaluateVector(E, Info.EvalResult.Val, Info)) return false; - } else if (getType()->isIntegerType()) { - if (!IntExprEvaluator(Info, Result.Val).Visit(const_cast<Expr*>(this))) + } else if (E->getType()->isIntegerType()) { + if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(const_cast<Expr*>(E))) return false; - } else if (getType()->hasPointerRepresentation()) { - if (!EvaluatePointer(this, Result.Val, Info)) - return false; - } else if (getType()->isRealFloatingType()) { - llvm::APFloat f(0.0); - if (!EvaluateFloat(this, f, Info)) - return false; - - Result.Val = APValue(f); - } else if (getType()->isAnyComplexType()) { - if (!EvaluateComplex(this, Result.Val, Info)) - return false; - } else - return false; - - return true; -} - -bool Expr::EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const { - EvalInfo Info(Ctx, Result, true); - - if (getType()->isVectorType()) { - if (!EvaluateVector(this, Result.Val, Info)) - return false; - } else if (getType()->isIntegerType()) { - if (!IntExprEvaluator(Info, Result.Val).Visit(const_cast<Expr*>(this))) + } else if (E->getType()->hasPointerRepresentation()) { + LValue LV; + if (!EvaluatePointer(E, LV, Info)) return false; - } else if (getType()->hasPointerRepresentation()) { - if (!EvaluatePointer(this, Result.Val, Info)) + if (!IsGlobalLValue(LV.Base)) return false; - } else if (getType()->isRealFloatingType()) { - llvm::APFloat f(0.0); - if (!EvaluateFloat(this, f, Info)) + LV.moveInto(Info.EvalResult.Val); + } else if (E->getType()->isRealFloatingType()) { + llvm::APFloat F(0.0); + if (!EvaluateFloat(E, F, Info)) return false; - Result.Val = APValue(f); - } else if (getType()->isAnyComplexType()) { - if (!EvaluateComplex(this, Result.Val, Info)) + Info.EvalResult.Val = APValue(F); + } else if (E->getType()->isAnyComplexType()) { + ComplexValue C; + if (!EvaluateComplex(E, C, Info)) return false; + C.moveInto(Info.EvalResult.Val); } else return false; @@ -2128,13 +2220,25 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const { bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); - return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects; + LValue LV; + if (EvaluateLValue(this, LV, Info) && + !Result.HasSideEffects && + IsGlobalLValue(LV.Base)) { + LV.moveInto(Result.Val); + return true; + } + return false; } bool Expr::EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const { - EvalInfo Info(Ctx, Result, true); + EvalInfo Info(Ctx, Result); - return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects; + LValue LV; + if (EvaluateLValue(this, LV, Info)) { + LV.moveInto(Result.Val); + return true; + } + return false; } /// isEvaluatable - Call Evaluate to see if this expression can be constant @@ -2159,3 +2263,388 @@ APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const { return EvalResult.Val.getInt(); } + + bool Expr::EvalResult::isGlobalLValue() const { + assert(Val.isLValue()); + return IsGlobalLValue(Val.getLValueBase()); + } + + +/// isIntegerConstantExpr - this recursive routine will test if an expression is +/// an integer constant expression. + +/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero, +/// comma, etc +/// +/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof +/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer +/// cast+dereference. + +// CheckICE - This function does the fundamental ICE checking: the returned +// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation. +// Note that to reduce code duplication, this helper does no evaluation +// itself; the caller checks whether the expression is evaluatable, and +// in the rare cases where CheckICE actually cares about the evaluated +// value, it calls into Evalute. +// +// Meanings of Val: +// 0: This expression is an ICE if it can be evaluated by Evaluate. +// 1: This expression is not an ICE, but if it isn't evaluated, it's +// a legal subexpression for an ICE. This return value is used to handle +// the comma operator in C99 mode. +// 2: This expression is not an ICE, and is not a legal subexpression for one. + +struct ICEDiag { + unsigned Val; + SourceLocation Loc; + + public: + ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {} + ICEDiag() : Val(0) {} +}; + +ICEDiag NoDiag() { return ICEDiag(); } + +static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) { + Expr::EvalResult EVResult; + if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || + !EVResult.Val.isInt()) { + return ICEDiag(2, E->getLocStart()); + } + return NoDiag(); +} + +static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { + assert(!E->isValueDependent() && "Should not see value dependent exprs!"); + if (!E->getType()->isIntegralType()) { + return ICEDiag(2, E->getLocStart()); + } + + switch (E->getStmtClass()) { +#define STMT(Node, Base) case Expr::Node##Class: +#define EXPR(Node, Base) +#include "clang/AST/StmtNodes.inc" + case Expr::PredefinedExprClass: + case Expr::FloatingLiteralClass: + case Expr::ImaginaryLiteralClass: + case Expr::StringLiteralClass: + case Expr::ArraySubscriptExprClass: + case Expr::MemberExprClass: + case Expr::CompoundAssignOperatorClass: + case Expr::CompoundLiteralExprClass: + case Expr::ExtVectorElementExprClass: + case Expr::InitListExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::ParenListExprClass: + case Expr::VAArgExprClass: + case Expr::AddrLabelExprClass: + case Expr::StmtExprClass: + case Expr::CXXMemberCallExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXTypeidExprClass: + case Expr::CXXNullPtrLiteralExprClass: + case Expr::CXXThisExprClass: + case Expr::CXXThrowExprClass: + case Expr::CXXNewExprClass: + case Expr::CXXDeleteExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::UnresolvedLookupExprClass: + case Expr::DependentScopeDeclRefExprClass: + case Expr::CXXConstructExprClass: + case Expr::CXXBindTemporaryExprClass: + case Expr::CXXBindReferenceExprClass: + case Expr::CXXExprWithTemporariesClass: + case Expr::CXXTemporaryObjectExprClass: + case Expr::CXXUnresolvedConstructExprClass: + case Expr::CXXDependentScopeMemberExprClass: + case Expr::UnresolvedMemberExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCMessageExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCImplicitSetterGetterRefExprClass: + case Expr::ObjCSuperExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::BlockExprClass: + case Expr::BlockDeclRefExprClass: + case Expr::NoStmtClass: + return ICEDiag(2, E->getLocStart()); + + case Expr::GNUNullExprClass: + // GCC considers the GNU __null value to be an integral constant expression. + return NoDiag(); + + case Expr::ParenExprClass: + return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx); + case Expr::IntegerLiteralClass: + case Expr::CharacterLiteralClass: + case Expr::CXXBoolLiteralExprClass: + case Expr::CXXZeroInitValueExprClass: + case Expr::TypesCompatibleExprClass: + case Expr::UnaryTypeTraitExprClass: + return NoDiag(); + case Expr::CallExprClass: + case Expr::CXXOperatorCallExprClass: { + const CallExpr *CE = cast<CallExpr>(E); + if (CE->isBuiltinCall(Ctx)) + return CheckEvalInICE(E, Ctx); + return ICEDiag(2, E->getLocStart()); + } + case Expr::DeclRefExprClass: + if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) + return NoDiag(); + if (Ctx.getLangOptions().CPlusPlus && + E->getType().getCVRQualifiers() == Qualifiers::Const) { + const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); + + // Parameter variables are never constants. Without this check, + // getAnyInitializer() can find a default argument, which leads + // to chaos. + if (isa<ParmVarDecl>(D)) + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + + // C++ 7.1.5.1p2 + // A variable of non-volatile const-qualified integral or enumeration + // type initialized by an ICE can be used in ICEs. + if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) { + Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers(); + if (Quals.hasVolatile() || !Quals.hasConst()) + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + + // Look for a declaration of this variable that has an initializer. + const VarDecl *ID = 0; + const Expr *Init = Dcl->getAnyInitializer(ID); + if (Init) { + if (ID->isInitKnownICE()) { + // We have already checked whether this subexpression is an + // integral constant expression. + if (ID->isInitICE()) + return NoDiag(); + else + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + } + + // It's an ICE whether or not the definition we found is + // out-of-line. See DR 721 and the discussion in Clang PR + // 6206 for details. + + if (Dcl->isCheckingICE()) { + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + } + + Dcl->setCheckingICE(); + ICEDiag Result = CheckICE(Init, Ctx); + // Cache the result of the ICE test. + Dcl->setInitKnownICE(Result.Val == 0); + return Result; + } + } + } + return ICEDiag(2, E->getLocStart()); + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast<UnaryOperator>(E); + switch (Exp->getOpcode()) { + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + case UnaryOperator::AddrOf: + case UnaryOperator::Deref: + return ICEDiag(2, E->getLocStart()); + case UnaryOperator::Extension: + case UnaryOperator::LNot: + case UnaryOperator::Plus: + case UnaryOperator::Minus: + case UnaryOperator::Not: + case UnaryOperator::Real: + case UnaryOperator::Imag: + return CheckICE(Exp->getSubExpr(), Ctx); + case UnaryOperator::OffsetOf: + break; + } + + // OffsetOf falls through here. + } + case Expr::OffsetOfExprClass: { + // Note that per C99, offsetof must be an ICE. And AFAIK, using + // Evaluate matches the proposed gcc behavior for cases like + // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect + // compliance: we should warn earlier for offsetof expressions with + // array subscripts that aren't ICEs, and if the array subscripts + // are ICEs, the value of the offsetof must be an integer constant. + return CheckEvalInICE(E, Ctx); + } + case Expr::SizeOfAlignOfExprClass: { + const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E); + if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType()) + return ICEDiag(2, E->getLocStart()); + return NoDiag(); + } + case Expr::BinaryOperatorClass: { + const BinaryOperator *Exp = cast<BinaryOperator>(E); + switch (Exp->getOpcode()) { + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + case BinaryOperator::Assign: + case BinaryOperator::MulAssign: + case BinaryOperator::DivAssign: + case BinaryOperator::RemAssign: + case BinaryOperator::AddAssign: + case BinaryOperator::SubAssign: + case BinaryOperator::ShlAssign: + case BinaryOperator::ShrAssign: + case BinaryOperator::AndAssign: + case BinaryOperator::XorAssign: + case BinaryOperator::OrAssign: + return ICEDiag(2, E->getLocStart()); + + case BinaryOperator::Mul: + case BinaryOperator::Div: + case BinaryOperator::Rem: + case BinaryOperator::Add: + case BinaryOperator::Sub: + case BinaryOperator::Shl: + case BinaryOperator::Shr: + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + case BinaryOperator::And: + case BinaryOperator::Xor: + case BinaryOperator::Or: + case BinaryOperator::Comma: { + ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); + ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); + if (Exp->getOpcode() == BinaryOperator::Div || + Exp->getOpcode() == BinaryOperator::Rem) { + // Evaluate gives an error for undefined Div/Rem, so make sure + // we don't evaluate one. + if (LHSResult.Val != 2 && RHSResult.Val != 2) { + llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx); + if (REval == 0) + return ICEDiag(1, E->getLocStart()); + if (REval.isSigned() && REval.isAllOnesValue()) { + llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx); + if (LEval.isMinSignedValue()) + return ICEDiag(1, E->getLocStart()); + } + } + } + if (Exp->getOpcode() == BinaryOperator::Comma) { + if (Ctx.getLangOptions().C99) { + // C99 6.6p3 introduces a strange edge case: comma can be in an ICE + // if it isn't evaluated. + if (LHSResult.Val == 0 && RHSResult.Val == 0) + return ICEDiag(1, E->getLocStart()); + } else { + // In both C89 and C++, commas in ICEs are illegal. + return ICEDiag(2, E->getLocStart()); + } + } + if (LHSResult.Val >= RHSResult.Val) + return LHSResult; + return RHSResult; + } + case BinaryOperator::LAnd: + case BinaryOperator::LOr: { + ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); + ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); + if (LHSResult.Val == 0 && RHSResult.Val == 1) { + // Rare case where the RHS has a comma "side-effect"; we need + // to actually check the condition to see whether the side + // with the comma is evaluated. + if ((Exp->getOpcode() == BinaryOperator::LAnd) != + (Exp->getLHS()->EvaluateAsInt(Ctx) == 0)) + return RHSResult; + return NoDiag(); + } + + if (LHSResult.Val >= RHSResult.Val) + return LHSResult; + return RHSResult; + } + } + } + case Expr::ImplicitCastExprClass: + case Expr::CStyleCastExprClass: + case Expr::CXXFunctionalCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: { + const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr(); + if (SubExpr->getType()->isIntegralType()) + return CheckICE(SubExpr, Ctx); + if (isa<FloatingLiteral>(SubExpr->IgnoreParens())) + return NoDiag(); + return ICEDiag(2, E->getLocStart()); + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast<ConditionalOperator>(E); + // If the condition (ignoring parens) is a __builtin_constant_p call, + // then only the true side is actually considered in an integer constant + // expression, and it is fully evaluated. This is an important GNU + // extension. See GCC PR38377 for discussion. + if (const CallExpr *CallCE + = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts())) + if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) { + Expr::EvalResult EVResult; + if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || + !EVResult.Val.isInt()) { + return ICEDiag(2, E->getLocStart()); + } + return NoDiag(); + } + ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx); + ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx); + ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); + if (CondResult.Val == 2) + return CondResult; + if (TrueResult.Val == 2) + return TrueResult; + if (FalseResult.Val == 2) + return FalseResult; + if (CondResult.Val == 1) + return CondResult; + if (TrueResult.Val == 0 && FalseResult.Val == 0) + return NoDiag(); + // Rare case where the diagnostics depend on which side is evaluated + // Note that if we get here, CondResult is 0, and at least one of + // TrueResult and FalseResult is non-zero. + if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) { + return FalseResult; + } + return TrueResult; + } + case Expr::CXXDefaultArgExprClass: + return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); + case Expr::ChooseExprClass: { + return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); + } + } + + // Silence a GCC warning + return ICEDiag(2, E->getLocStart()); +} + +bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, + SourceLocation *Loc, bool isEvaluated) const { + ICEDiag d = CheckICE(this, Ctx); + if (d.Val != 0) { + if (Loc) *Loc = d.Loc; + return false; + } + EvalResult EvalResult; + if (!Evaluate(EvalResult, Ctx)) + llvm_unreachable("ICE cannot be evaluated!"); + assert(!EvalResult.HasSideEffects && "ICE with side effects!"); + assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); + Result = EvalResult.Val.getInt(); + return true; +} diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 45518e98bc15..d6594cdfd02f 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -145,14 +145,14 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS, InnerPolicy.SuppressScope = true; // Nested-name-specifiers are intended to contain minimally-qualified - // types. An actual QualifiedNameType will not occur, since we'll store + // types. An actual ElaboratedType will not occur, since we'll store // just the type that is referred to in the nested-name-specifier (e.g., // a TypedefType, TagType, etc.). However, when we are dealing with // dependent template-id types (e.g., Outer<T>::template Inner<U>), // the type requires its own nested-name-specifier for uniqueness, so we // suppress that nested-name-specifier during printing. - assert(!isa<QualifiedNameType>(T) && - "Qualified name type in nested-name-specifier"); + assert(!isa<ElaboratedType>(T) && + "Elaborated type in nested-name-specifier"); if (const TemplateSpecializationType *SpecType = dyn_cast<TemplateSpecializationType>(T)) { // Print the template name without its corresponding diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp index ade2483722ef..262c4597f846 100644 --- a/lib/AST/RecordLayout.cpp +++ b/lib/AST/RecordLayout.cpp @@ -44,7 +44,9 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, unsigned fieldcount, uint64_t nonvirtualsize, unsigned nonvirtualalign, - const PrimaryBaseInfo &PrimaryBase, + uint64_t SizeOfLargestEmptySubobject, + const CXXRecordDecl *PrimaryBase, + bool PrimaryBaseIsVirtual, const BaseOffsetsMapTy& BaseOffsets, const BaseOffsetsMapTy& VBaseOffsets) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), @@ -55,9 +57,10 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, memcpy(FieldOffsets, fieldoffsets, FieldCount * sizeof(*FieldOffsets)); } - CXXInfo->PrimaryBase = PrimaryBase; + CXXInfo->PrimaryBase = PrimaryBaseInfo(PrimaryBase, PrimaryBaseIsVirtual); CXXInfo->NonVirtualSize = nonvirtualsize; CXXInfo->NonVirtualAlign = nonvirtualalign; + CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject; CXXInfo->BaseOffsets = BaseOffsets; CXXInfo->VBaseOffsets = VBaseOffsets; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 3782985e5302..983a2874a735 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -1,4 +1,4 @@ -//=== ASTRecordLayoutBuilder.cpp - Helper class for building record layouts ==// +//=== RecordLayoutBuilder.cpp - Helper class for building record layouts ---==// // // The LLVM Compiler Infrastructure // @@ -7,28 +7,443 @@ // //===----------------------------------------------------------------------===// -#include "RecordLayoutBuilder.h" - #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Support/Format.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Support/MathExtras.h" +#include <map> using namespace clang; -ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Context) - : Context(Context), Size(0), Alignment(8), Packed(false), - UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), IsUnion(false), - NonVirtualSize(0), NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { } +namespace { + +/// EmptySubobjectMap - Keeps track of which empty subobjects exist at different +/// offsets while laying out a C++ class. +class EmptySubobjectMap { + ASTContext &Context; + + /// Class - The class whose empty entries we're keeping track of. + const CXXRecordDecl *Class; + + /// EmptyClassOffsets - A map from offsets to empty record decls. + typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy; + typedef llvm::DenseMap<uint64_t, ClassVectorTy> EmptyClassOffsetsMapTy; + EmptyClassOffsetsMapTy EmptyClassOffsets; + + /// ComputeEmptySubobjectSizes - Compute the size of the largest base or + /// member subobject that is empty. + void ComputeEmptySubobjectSizes(); + + struct BaseInfo { + const CXXRecordDecl *Class; + bool IsVirtual; + + const CXXRecordDecl *PrimaryVirtualBase; + + llvm::SmallVector<BaseInfo*, 4> Bases; + const BaseInfo *Derived; + }; + + llvm::DenseMap<const CXXRecordDecl *, BaseInfo *> VirtualBaseInfo; + llvm::DenseMap<const CXXRecordDecl *, BaseInfo *> NonVirtualBaseInfo; + + BaseInfo *ComputeBaseInfo(const CXXRecordDecl *RD, bool IsVirtual, + const BaseInfo *Derived); + void ComputeBaseInfo(); + + bool CanPlaceBaseSubobjectAtOffset(const BaseInfo *Info, uint64_t Offset); + void UpdateEmptyBaseSubobjects(const BaseInfo *Info, uint64_t Offset); + +public: + /// This holds the size of the largest empty subobject (either a base + /// or a member). Will be zero if the record being built doesn't contain + /// any empty classes. + uint64_t SizeOfLargestEmptySubobject; + + EmptySubobjectMap(ASTContext &Context, const CXXRecordDecl *Class) + : Context(Context), Class(Class), SizeOfLargestEmptySubobject(0) { + ComputeEmptySubobjectSizes(); + + ComputeBaseInfo(); + } + + /// CanPlaceBaseAtOffset - Return whether the given base class can be placed + /// at the given offset. + /// Returns false if placing the record will result in two components + /// (direct or indirect) of the same type having the same offset. + bool CanPlaceBaseAtOffset(const CXXRecordDecl *RD, bool BaseIsVirtual, + uint64_t Offset); +}; + +void EmptySubobjectMap::ComputeEmptySubobjectSizes() { + // Check the bases. + for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), + E = Class->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + uint64_t EmptySize = 0; + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); + if (BaseDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); + } + + SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject, + EmptySize); + } + + // Check the fields. + for (CXXRecordDecl::field_iterator I = Class->field_begin(), + E = Class->field_end(); I != E; ++I) { + const FieldDecl *FD = *I; + + const RecordType *RT = + Context.getBaseElementType(FD->getType())->getAs<RecordType>(); + + // We only care about record types. + if (!RT) + continue; + + uint64_t EmptySize = 0; + const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl()); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); + if (MemberDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); + } + + SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject, + EmptySize); + } +} + +EmptySubobjectMap::BaseInfo * +EmptySubobjectMap::ComputeBaseInfo(const CXXRecordDecl *RD, bool IsVirtual, + const BaseInfo *Derived) { + BaseInfo *Info; + + if (IsVirtual) { + BaseInfo *&InfoSlot = VirtualBaseInfo[RD]; + if (InfoSlot) { + assert(InfoSlot->Class == RD && "Wrong class for virtual base info!"); + return InfoSlot; + } + + InfoSlot = new (Context) BaseInfo; + Info = InfoSlot; + } else { + Info = new (Context) BaseInfo; + } + + Info->Class = RD; + Info->IsVirtual = IsVirtual; + Info->Derived = Derived; + Info->PrimaryVirtualBase = 0; + + if (RD->getNumVBases()) { + // Check if this class has a primary virtual base. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + if (Layout.getPrimaryBaseWasVirtual()) { + Info->PrimaryVirtualBase = Layout.getPrimaryBase(); + assert(Info->PrimaryVirtualBase && + "Didn't have a primary virtual base!"); + } + } + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + bool IsVirtual = I->isVirtual(); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + Info->Bases.push_back(ComputeBaseInfo(BaseDecl, IsVirtual, Info)); + } + + return Info; +} + +void EmptySubobjectMap::ComputeBaseInfo() { + for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), + E = Class->bases_end(); I != E; ++I) { + bool IsVirtual = I->isVirtual(); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + BaseInfo *Info = ComputeBaseInfo(BaseDecl, IsVirtual, /*Derived=*/0); + if (IsVirtual) { + // ComputeBaseInfo has already added this base for us. + continue; + } + + // Add the base info to the map of non-virtual bases. + assert(!NonVirtualBaseInfo.count(BaseDecl) && + "Non-virtual base already exists!"); + NonVirtualBaseInfo.insert(std::make_pair(BaseDecl, Info)); + } +} + +bool +EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseInfo *Info, + uint64_t Offset) { + // Traverse all non-virtual bases. + for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) { + BaseInfo* Base = Info->Bases[I]; + if (Base->IsVirtual) + continue; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class); + uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); + + if (!CanPlaceBaseSubobjectAtOffset(Base, BaseOffset)) + return false; + } + + if (Info->PrimaryVirtualBase) { + BaseInfo *PrimaryVirtualBaseInfo = + VirtualBaseInfo.lookup(Info->PrimaryVirtualBase); + assert(PrimaryVirtualBaseInfo && "Didn't find base info!"); + + if (Info == PrimaryVirtualBaseInfo->Derived) { + if (!CanPlaceBaseSubobjectAtOffset(PrimaryVirtualBaseInfo, Offset)) + return false; + } + } + + // FIXME: Member variables. + return true; +} + +void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseInfo *Info, + uint64_t Offset) { + if (Info->Class->isEmpty()) { + // FIXME: Record that there is an empty class at this offset. + } + + // Traverse all non-virtual bases. + for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) { + BaseInfo* Base = Info->Bases[I]; + if (Base->IsVirtual) + continue; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class); + uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); + + UpdateEmptyBaseSubobjects(Base, BaseOffset); + } + + if (Info->PrimaryVirtualBase) { + BaseInfo *PrimaryVirtualBaseInfo = + VirtualBaseInfo.lookup(Info->PrimaryVirtualBase); + assert(PrimaryVirtualBaseInfo && "Didn't find base info!"); + + if (Info == PrimaryVirtualBaseInfo->Derived) + UpdateEmptyBaseSubobjects(PrimaryVirtualBaseInfo, Offset); + } + + // FIXME: Member variables. +} + +bool EmptySubobjectMap::CanPlaceBaseAtOffset(const CXXRecordDecl *RD, + bool BaseIsVirtual, + uint64_t Offset) { + // If we know this class doesn't have any empty subobjects we don't need to + // bother checking. + if (!SizeOfLargestEmptySubobject) + return true; + + BaseInfo *Info; + + if (BaseIsVirtual) + Info = VirtualBaseInfo.lookup(RD); + else + Info = NonVirtualBaseInfo.lookup(RD); + + if (!CanPlaceBaseSubobjectAtOffset(Info, Offset)) + return false; + + UpdateEmptyBaseSubobjects(Info, Offset); + return true; +} + +class RecordLayoutBuilder { + // FIXME: Remove this and make the appropriate fields public. + friend class clang::ASTContext; + + ASTContext &Context; + + EmptySubobjectMap *EmptySubobjects; + + /// Size - The current size of the record layout. + uint64_t Size; + + /// Alignment - The current alignment of the record layout. + unsigned Alignment; + + llvm::SmallVector<uint64_t, 16> FieldOffsets; + + /// Packed - Whether the record is packed or not. + unsigned Packed : 1; + + unsigned IsUnion : 1; + + unsigned IsMac68kAlign : 1; + + /// UnfilledBitsInLastByte - If the last field laid out was a bitfield, + /// this contains the number of bits in the last byte that can be used for + /// an adjacent bitfield if necessary. + unsigned char UnfilledBitsInLastByte; + + /// MaxFieldAlignment - The maximum allowed field alignment. This is set by + /// #pragma pack. + unsigned MaxFieldAlignment; + + /// DataSize - The data size of the record being laid out. + uint64_t DataSize; + + uint64_t NonVirtualSize; + unsigned NonVirtualAlignment; + + /// PrimaryBase - the primary base class (if one exists) of the class + /// we're laying out. + const CXXRecordDecl *PrimaryBase; + + /// PrimaryBaseIsVirtual - Whether the primary base of the class we're laying + /// out is virtual. + bool PrimaryBaseIsVirtual; + + typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy; + + /// Bases - base classes and their offsets in the record. + BaseOffsetsMapTy Bases; + + // VBases - virtual base classes and their offsets in the record. + 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; + + RecordLayoutBuilder(ASTContext &Context, EmptySubobjectMap *EmptySubobjects) + : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(8), + Packed(false), IsUnion(false), IsMac68kAlign(false), + UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), + NonVirtualSize(0), NonVirtualAlignment(8), PrimaryBase(0), + PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { } + + void Layout(const RecordDecl *D); + void Layout(const CXXRecordDecl *D); + void Layout(const ObjCInterfaceDecl *D); + + void LayoutFields(const RecordDecl *D); + void LayoutField(const FieldDecl *D); + void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize); + void LayoutBitField(const FieldDecl *D); + + /// ComputeEmptySubobjectSizes - Compute the size of the largest base or + /// member subobject that is empty. + void ComputeEmptySubobjectSizes(const CXXRecordDecl *RD); + + /// 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); + + 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 *Base); + + void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, + const CXXRecordDecl *MostDerivedClass); + + /// LayoutVirtualBases - Lays out all the virtual bases. + void LayoutVirtualBases(const CXXRecordDecl *RD, + const CXXRecordDecl *MostDerivedClass); + + /// LayoutVirtualBase - Lays out a single virtual base. + void LayoutVirtualBase(const CXXRecordDecl *Base); + + /// LayoutBase - Will lay out a base and return the offset where it was + /// placed, in bits. + uint64_t LayoutBase(const CXXRecordDecl *Base, bool BaseIsVirtual); + + /// canPlaceRecordAtOffset - Return whether a record (either a base class + /// or a field) can be placed at the given offset. + /// Returns false if placing the record will result in two components + /// (direct or indirect) of the same type having the same offset. + bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset, + bool CheckVBases) const; + + /// canPlaceFieldAtOffset - Return whether a field can be placed at the given + /// offset. + bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const; + + /// UpdateEmptyClassOffsets - Called after a record (either a base class + /// or a field) has been placed at the given offset. Will update the + /// EmptyClassOffsets map if the class is empty or has any empty bases or + /// fields. + void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset, + bool UpdateVBases); + + /// UpdateEmptyClassOffsets - Called after a field has been placed at the + /// given offset. + void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset); + + /// InitializeLayout - Initialize record layout for the given record decl. + void InitializeLayout(const Decl *D); + + /// FinishLayout - Finalize record layout. Adjust record size based on the + /// alignment. + void FinishLayout(); + + void UpdateAlignment(unsigned NewAlignment); + + RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT + void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT +public: + static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); +}; +} // end anonymous namespace /// IsNearlyEmpty - Indicates when a class has a vtable pointer, but /// no other data. -bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { +bool RecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { // FIXME: Audit the corners if (!RD->isDynamicClass()) return false; @@ -38,7 +453,7 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { return false; } -void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { +void RecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = Context.getASTRecordLayout(RD).getPrimaryBaseInfo(); @@ -63,7 +478,7 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { } void -ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { +RecordLayoutBuilder::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() && @@ -77,8 +492,8 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { // If it's not an indirect primary base, then we've found our primary // base. if (!IndirectPrimaryBases.count(Base)) { - PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, - /*IsVirtual=*/true); + PrimaryBase = Base; + PrimaryBaseIsVirtual = true; return; } @@ -88,13 +503,13 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { } SelectPrimaryVBase(Base); - if (PrimaryBase.getBase()) + if (PrimaryBase) return; } } /// DeterminePrimaryBase - Determine the primary base of the given class. -void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { +void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // If the class isn't dynamic, it won't have a primary base. if (!RD->isDynamicClass()) return; @@ -124,7 +539,8 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { if (Base->isDynamicClass()) { // We found it. - PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, /*IsVirtual=*/false); + PrimaryBase = Base; + PrimaryBaseIsVirtual = false; return; } } @@ -133,20 +549,20 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // indirect primary virtual base class, if one exists. if (RD->getNumVBases() != 0) { SelectPrimaryVBase(RD); - if (PrimaryBase.getBase()) + if (PrimaryBase) return; } // 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); + PrimaryBase = FirstNearlyEmptyVBase; + PrimaryBaseIsVirtual = true; return; } // Otherwise there is no primary base class. - assert(!PrimaryBase.getBase() && "Should not get here with a primary base!"); + assert(!PrimaryBase && "Should not get here with a primary base!"); // Allocate the virtual table pointer at offset zero. assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); @@ -160,22 +576,23 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { } void -ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { +RecordLayoutBuilder::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()) { + if (PrimaryBase) { + if (PrimaryBaseIsVirtual) { // We have a virtual primary base, insert it as an indirect primary base. - IndirectPrimaryBases.insert(Base); + IndirectPrimaryBases.insert(PrimaryBase); - assert(!VisitedVirtualBases.count(Base) && "vbase already visited!"); - VisitedVirtualBases.insert(Base); - - LayoutVirtualBase(Base); + assert(!VisitedVirtualBases.count(PrimaryBase) && + "vbase already visited!"); + VisitedVirtualBases.insert(PrimaryBase); + + LayoutVirtualBase(PrimaryBase); } else - LayoutNonVirtualBase(Base); + LayoutNonVirtualBase(PrimaryBase); } // Now lay out the non-virtual bases. @@ -190,7 +607,7 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); // Skip the primary base. - if (Base == PrimaryBase.getBase() && !PrimaryBase.isVirtual()) + if (Base == PrimaryBase && !PrimaryBaseIsVirtual) continue; // Lay out the base. @@ -198,17 +615,17 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { } } -void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) { +void RecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *Base) { // Layout the base. - uint64_t Offset = LayoutBase(RD); + uint64_t Offset = LayoutBase(Base, /*BaseIsVirtual=*/false); // Add its base class offset. - if (!Bases.insert(std::make_pair(RD, Offset)).second) + if (!Bases.insert(std::make_pair(Base, Offset)).second) assert(false && "Added same base offset more than once!"); } void -ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, +RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, const CXXRecordDecl *MostDerivedClass) { // We already have the offset for the primary base of the most derived class. @@ -226,7 +643,7 @@ ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); - + const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); @@ -234,17 +651,17 @@ ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, // 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()) { // If we don't know this vbase yet, don't visit it. It will be visited // later. if (!VBases.count(BaseDecl)) { continue; } - + // Check if we've already visited this base. if (!VisitedVirtualBases.insert(BaseDecl)) continue; @@ -265,14 +682,14 @@ ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, } void -ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, +RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass) { const CXXRecordDecl *PrimaryBase; bool PrimaryBaseIsVirtual; if (MostDerivedClass == RD) { - PrimaryBase = this->PrimaryBase.getBase(); - PrimaryBaseIsVirtual = this->PrimaryBase.isVirtual(); + PrimaryBase = this->PrimaryBase; + PrimaryBaseIsVirtual = this->PrimaryBaseIsVirtual; } else { const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); PrimaryBase = Layout.getPrimaryBase(); @@ -296,7 +713,7 @@ ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, // Only visit virtual bases once. if (!VisitedVirtualBases.insert(Base)) continue; - + LayoutVirtualBase(Base); } } @@ -311,58 +728,64 @@ ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, } } -void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { +void RecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *Base) { // Layout the base. - uint64_t Offset = LayoutBase(RD); + uint64_t Offset = LayoutBase(Base, /*BaseIsVirtual=*/true); // Add its base class offset. - if (!VBases.insert(std::make_pair(RD, Offset)).second) + if (!VBases.insert(std::make_pair(Base, Offset)).second) assert(false && "Added same vbase offset more than once!"); } -uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { - const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); +uint64_t RecordLayoutBuilder::LayoutBase(const CXXRecordDecl *Base, + bool BaseIsVirtual) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base); // If we have an empty base class, try to place it at offset 0. - if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) { + if (Base->isEmpty() && + EmptySubobjects->CanPlaceBaseAtOffset(Base, BaseIsVirtual, 0) && + canPlaceRecordAtOffset(Base, 0, /*CheckVBases=*/false)) { // We were able to place the class at offset 0. - UpdateEmptyClassOffsets(RD, 0); + UpdateEmptyClassOffsets(Base, 0, /*UpdateVBases=*/false); - Size = std::max(Size, BaseInfo.getSize()); + Size = std::max(Size, Layout.getSize()); return 0; } - unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); + unsigned BaseAlign = Layout.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)) + if (EmptySubobjects->CanPlaceBaseAtOffset(Base, BaseIsVirtual, Offset) && + canPlaceRecordAtOffset(Base, Offset, /*CheckVBases=*/false)) break; Offset += BaseAlign; } - if (!RD->isEmpty()) { + if (!Base->isEmpty()) { // Update the data size. - DataSize = Offset + BaseInfo.getNonVirtualSize(); + DataSize = Offset + Layout.getNonVirtualSize(); Size = std::max(Size, DataSize); } else - Size = std::max(Size, Offset + BaseInfo.getSize()); + Size = std::max(Size, Offset + Layout.getSize()); // Remember max struct/class alignment. UpdateAlignment(BaseAlign); - UpdateEmptyClassOffsets(RD, Offset); + UpdateEmptyClassOffsets(Base, Offset, /*UpdateVBases=*/false); return Offset; } -bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, - uint64_t Offset) const { +bool +RecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, + uint64_t Offset, + bool CheckVBases) const { // Look for an empty class with the same type at the same offset. for (EmptyClassOffsetsTy::const_iterator I = EmptyClassOffsets.lower_bound(Offset), @@ -372,7 +795,7 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, return false; } - const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); // Check bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), @@ -382,12 +805,13 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, if (I->isVirtual()) continue; - const CXXRecordDecl *Base = + const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); + uint64_t BaseOffset = Layout.getBaseClassOffset(BaseDecl); - if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset)) + if (!canPlaceRecordAtOffset(BaseDecl, Offset + BaseOffset, + /*CheckVBases=*/false)) return false; } @@ -397,22 +821,25 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; - uint64_t FieldOffset = Info.getFieldOffset(FieldNo); + uint64_t FieldOffset = Layout.getFieldOffset(FieldNo); if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset)) return false; } - // FIXME: virtual bases. + if (CheckVBases) { + // FIXME: virtual bases. + } + return true; } -bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, +bool RecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const { QualType T = FD->getType(); if (const RecordType *RT = T->getAs<RecordType>()) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) - return canPlaceRecordAtOffset(RD, Offset); + return canPlaceRecordAtOffset(RD, Offset, /*CheckVBases=*/true); } if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { @@ -424,27 +851,28 @@ bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, if (!RD) return true; - const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); uint64_t NumElements = Context.getConstantArrayElementCount(AT); uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { - if (!canPlaceRecordAtOffset(RD, ElementOffset)) + if (!canPlaceRecordAtOffset(RD, ElementOffset, /*CheckVBases=*/true)) return false; - ElementOffset += Info.getSize(); + ElementOffset += Layout.getSize(); } } return true; } -void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, - uint64_t Offset) { +void RecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, + uint64_t Offset, + bool UpdateVBases) { if (RD->isEmpty()) EmptyClassOffsets.insert(std::make_pair(Offset, RD)); - const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); // Update bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), @@ -457,8 +885,9 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, const CXXRecordDecl *Base = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); - UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset); + uint64_t BaseClassOffset = Layout.getBaseClassOffset(Base); + UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset, + /*UpdateVBases=*/false); } // Update fields. @@ -467,21 +896,30 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; - uint64_t FieldOffset = Info.getFieldOffset(FieldNo); + uint64_t FieldOffset = Layout.getFieldOffset(FieldNo); UpdateEmptyClassOffsets(FD, Offset + FieldOffset); } - // FIXME: Update virtual bases. + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (UpdateVBases) { + // FIXME: Update virtual bases. + } else if (PrimaryBase && Layout.getPrimaryBaseWasVirtual()) { + // We always want to update the offsets of a primary virtual base. + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "primary base class offset must always be 0!"); + UpdateEmptyClassOffsets(PrimaryBase, Offset, /*UpdateVBases=*/false); + } } void -ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, +RecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset) { QualType T = FD->getType(); if (const RecordType *RT = T->getAs<RecordType>()) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) { - UpdateEmptyClassOffsets(RD, Offset); + UpdateEmptyClassOffsets(RD, Offset, /*UpdateVBases=*/true); return; } } @@ -501,76 +939,90 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { - UpdateEmptyClassOffsets(RD, ElementOffset); + UpdateEmptyClassOffsets(RD, ElementOffset, /*UpdateVBases=*/true); ElementOffset += Info.getSize(); } } } -void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { - IsUnion = D->isUnion(); +void RecordLayoutBuilder::InitializeLayout(const Decl *D) { + if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) + IsUnion = RD->isUnion(); Packed = D->hasAttr<PackedAttr>(); - // The #pragma pack attribute specifies the maximum field alignment. - if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>()) - MaxFieldAlignment = PPA->getAlignment(); - - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - UpdateAlignment(AA->getMaxAlignment()); + // mac68k alignment supersedes maximum field alignment and attribute aligned, + // and forces all structures to have 2-byte alignment. The IBM docs on it + // allude to additional (more complicated) semantics, especially with regard + // to bit-fields, but gcc appears not to follow that. + if (D->hasAttr<AlignMac68kAttr>()) { + IsMac68kAlign = true; + MaxFieldAlignment = 2 * 8; + Alignment = 2 * 8; + } else { + if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>()) + MaxFieldAlignment = MFAA->getAlignment(); - // If this is a C++ class, lay out the vtable and the non-virtual bases. - const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D); - if (RD) - LayoutNonVirtualBases(RD); + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + UpdateAlignment(AA->getMaxAlignment()); + } +} +void RecordLayoutBuilder::Layout(const RecordDecl *D) { + InitializeLayout(D); LayoutFields(D); + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + FinishLayout(); +} + +void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { + InitializeLayout(RD); + + // Lay out the vtable and the non-virtual bases. + LayoutNonVirtualBases(RD); + + LayoutFields(RD); + NonVirtualSize = Size; NonVirtualAlignment = Alignment; - // If this is a C++ class, lay out its virtual bases and add its primary - // virtual base offsets. - if (RD) { - LayoutVirtualBases(RD, RD); + // Lay out the virtual bases and add the primary virtual base offsets. + LayoutVirtualBases(RD, RD); - VisitedVirtualBases.clear(); - AddPrimaryVirtualBaseOffsets(RD, 0, RD); - } + VisitedVirtualBases.clear(); + AddPrimaryVirtualBaseOffsets(RD, 0, RD); // Finally, round the size of the total struct up to the alignment of the // struct itself. FinishLayout(); - + #ifndef NDEBUG - if (RD) { - // Check that we have base offsets for all bases. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - if (I->isVirtual()) - continue; - - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - assert(Bases.count(BaseDecl) && "Did not find base offset!"); - } - - // And all virtual bases. - for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), - E = RD->vbases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - assert(VBases.count(BaseDecl) && "Did not find base offset!"); - } + // Check that we have base offsets for all bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(Bases.count(BaseDecl) && "Did not find base offset!"); + } + + // And all virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(VBases.count(BaseDecl) && "Did not find base offset!"); } #endif } -// FIXME. Impl is no longer needed. -void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, - const ObjCImplementationDecl *Impl) { +void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { if (ObjCInterfaceDecl *SD = D->getSuperClass()) { const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD); @@ -582,14 +1034,8 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, DataSize = Size; } - Packed = D->hasAttr<PackedAttr>(); - - // The #pragma pack attribute specifies the maximum field alignment. - if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>()) - MaxFieldAlignment = PPA->getAlignment(); + InitializeLayout(D); - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - UpdateAlignment(AA->getMaxAlignment()); // Layout each ivar sequentially. llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; Context.ShallowCollectObjCIvars(D, Ivars); @@ -601,7 +1047,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, FinishLayout(); } -void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { +void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Layout each field, for now, just sequentially, respecting alignment. In // the future, this will need to be tweakable by targets. for (RecordDecl::field_iterator Field = D->field_begin(), @@ -609,17 +1055,17 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { LayoutField(*Field); } -void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, +void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize) { assert(Context.getLangOptions().CPlusPlus && "Can only have wide bit-fields in C++!"); - + // Itanium C++ ABI 2.4: - // If sizeof(T)*8 < n, let T' be the largest integral POD type with + // If sizeof(T)*8 < n, let T' be the largest integral POD type with // sizeof(T')*8 <= n. - + QualType IntegralPODTypes[] = { - Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy, + Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy }; @@ -634,24 +1080,24 @@ void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, Type = IntegralPODTypes[I]; } assert(!Type.isNull() && "Did not find a type!"); - + unsigned TypeAlign = Context.getTypeAlign(Type); // We're not going to use any of the unfilled bits in the last byte. UnfilledBitsInLastByte = 0; uint64_t FieldOffset; - + if (IsUnion) { DataSize = std::max(DataSize, FieldSize); FieldOffset = 0; } else { // The bitfield is allocated starting at the next offset aligned appropriately - // for T', with length n bits. + // for T', with length n bits. FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign); - + uint64_t NewSizeInBits = FieldOffset + FieldSize; - + DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8); UnfilledBitsInLastByte = DataSize - NewSizeInBits; } @@ -661,12 +1107,12 @@ void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, // Update the size. Size = std::max(Size, DataSize); - + // Remember max struct/class alignment. UpdateAlignment(TypeAlign); } -void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { +void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte); uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); @@ -718,7 +1164,7 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { UpdateAlignment(FieldAlign); } -void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { +void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { if (D->isBitField()) { LayoutBitField(D); return; @@ -791,7 +1237,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { UpdateAlignment(FieldAlign); } -void ASTRecordLayoutBuilder::FinishLayout() { +void RecordLayoutBuilder::FinishLayout() { // In C++, records cannot be of size 0. if (Context.getLangOptions().CPlusPlus && Size == 0) Size = 8; @@ -800,7 +1246,11 @@ void ASTRecordLayoutBuilder::FinishLayout() { Size = llvm::RoundUpToAlignment(Size, Alignment); } -void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { +void RecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { + // The alignment is not modified when using 'mac68k' alignment. + if (IsMac68kAlign) + return; + if (NewAlignment <= Alignment) return; @@ -809,55 +1259,8 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { Alignment = NewAlignment; } -const ASTRecordLayout * -ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, - const RecordDecl *D) { - ASTRecordLayoutBuilder Builder(Ctx); - - Builder.Layout(D); - - if (!isa<CXXRecordDecl>(D)) - return new (Ctx) ASTRecordLayout(Ctx, Builder.Size, Builder.Alignment, - Builder.Size, - Builder.FieldOffsets.data(), - Builder.FieldOffsets.size()); - - // FIXME: This is not always correct. See the part about bitfields at - // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. - // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. - bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD(); - - // FIXME: This should be done in FinalizeLayout. - uint64_t DataSize = - IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize; - uint64_t NonVirtualSize = - IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; - - return new (Ctx) ASTRecordLayout(Ctx, Builder.Size, Builder.Alignment, - DataSize, Builder.FieldOffsets.data(), - Builder.FieldOffsets.size(), - NonVirtualSize, - Builder.NonVirtualAlignment, - Builder.PrimaryBase, - Builder.Bases, Builder.VBases); -} - -const ASTRecordLayout * -ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, - const ObjCInterfaceDecl *D, - const ObjCImplementationDecl *Impl) { - ASTRecordLayoutBuilder Builder(Ctx); - - Builder.Layout(D, Impl); - - return new (Ctx) ASTRecordLayout(Ctx, Builder.Size, Builder.Alignment, - Builder.DataSize, - Builder.FieldOffsets.data(), - Builder.FieldOffsets.size()); -} - const CXXMethodDecl * -ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { +RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { assert(RD->isDynamicClass() && "Class does not have any virtual methods!"); // If a class isn't polymorphic it doesn't have a key function. @@ -898,6 +1301,124 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { return 0; } +/// getASTRecordLayout - Get or compute information about the layout of the +/// specified record (struct/union/class), which indicates its size and field +/// position information. +const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { + D = D->getDefinition(); + assert(D && "Cannot get layout of forward declarations!"); + + // Look up this layout, if already laid out, return what we have. + // Note that we can't save a reference to the entry because this function + // is recursive. + const ASTRecordLayout *Entry = ASTRecordLayouts[D]; + if (Entry) return *Entry; + + const ASTRecordLayout *NewEntry; + + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + EmptySubobjectMap EmptySubobjects(*this, RD); + + RecordLayoutBuilder Builder(*this, &EmptySubobjects); + Builder.Layout(RD); + + // FIXME: This is not always correct. See the part about bitfields at + // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. + // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. + bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD(); + + // FIXME: This should be done in FinalizeLayout. + uint64_t DataSize = + IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize; + uint64_t NonVirtualSize = + IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; + + NewEntry = + new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment, + DataSize, Builder.FieldOffsets.data(), + Builder.FieldOffsets.size(), + NonVirtualSize, + Builder.NonVirtualAlignment, + EmptySubobjects.SizeOfLargestEmptySubobject, + Builder.PrimaryBase, + Builder.PrimaryBaseIsVirtual, + Builder.Bases, Builder.VBases); + } else { + RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); + Builder.Layout(D); + + NewEntry = + new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment, + Builder.Size, + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size()); + } + + ASTRecordLayouts[D] = NewEntry; + + if (getLangOptions().DumpRecordLayouts) { + llvm::errs() << "\n*** Dumping AST Record Layout\n"; + DumpRecordLayout(D, llvm::errs()); + } + + return *NewEntry; +} + +const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { + RD = cast<CXXRecordDecl>(RD->getDefinition()); + assert(RD && "Cannot get key function for forward declarations!"); + + const CXXMethodDecl *&Entry = KeyFunctions[RD]; + if (!Entry) + Entry = RecordLayoutBuilder::ComputeKeyFunction(RD); + else + assert(Entry == RecordLayoutBuilder::ComputeKeyFunction(RD) && + "Key function changed!"); + + return Entry; +} + +/// getInterfaceLayoutImpl - Get or compute information about the +/// layout of the given interface. +/// +/// \param Impl - If given, also include the layout of the interface's +/// implementation. This may differ by including synthesized ivars. +const ASTRecordLayout & +ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl) { + assert(!D->isForwardDecl() && "Invalid interface decl!"); + + // Look up this layout, if already laid out, return what we have. + ObjCContainerDecl *Key = + Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D; + if (const ASTRecordLayout *Entry = ObjCLayouts[Key]) + return *Entry; + + // Add in synthesized ivar count if laying out an implementation. + if (Impl) { + unsigned SynthCount = CountNonClassIvars(D); + // If there aren't any sythesized ivars then reuse the interface + // entry. Note we can't cache this because we simply free all + // entries later; however we shouldn't look up implementations + // frequently. + if (SynthCount == 0) + return getObjCLayout(D, 0); + } + + RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); + Builder.Layout(D); + + const ASTRecordLayout *NewEntry = + new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment, + Builder.DataSize, + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size()); + + ObjCLayouts[Key] = NewEntry; + + return *NewEntry; +} + static void PrintOffset(llvm::raw_ostream &OS, uint64_t Offset, unsigned IndentLevel) { OS << llvm::format("%4d | ", Offset); diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h deleted file mode 100644 index f277c29398b3..000000000000 --- a/lib/AST/RecordLayoutBuilder.h +++ /dev/null @@ -1,170 +0,0 @@ -//===- ASTRecordLayoutBuilder.h - Helper class for building record layouts ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H -#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H - -#include "clang/AST/RecordLayout.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/System/DataTypes.h" -#include <map> - -namespace clang { - class ASTContext; - class ASTRecordLayout; - class CXXRecordDecl; - class FieldDecl; - class ObjCImplementationDecl; - class ObjCInterfaceDecl; - class RecordDecl; - -class ASTRecordLayoutBuilder { - ASTContext &Context; - - /// Size - The current size of the record layout. - uint64_t Size; - - /// Alignment - The current alignment of the record layout. - unsigned Alignment; - - llvm::SmallVector<uint64_t, 16> FieldOffsets; - - /// Packed - Whether the record is packed or not. - bool Packed; - - /// UnfilledBitsInLastByte - If the last field laid out was a bitfield, - /// this contains the number of bits in the last byte that can be used for - /// an adjacent bitfield if necessary. - unsigned char UnfilledBitsInLastByte; - - /// MaxFieldAlignment - The maximum allowed field alignment. This is set by - /// #pragma pack. - unsigned MaxFieldAlignment; - - /// DataSize - The data size of the record being laid out. - uint64_t DataSize; - - bool IsUnion; - - uint64_t NonVirtualSize; - unsigned NonVirtualAlignment; - - /// PrimaryBase - the primary base class (if one exists) of the class - /// we're laying out. - ASTRecordLayout::PrimaryBaseInfo PrimaryBase; - - /// Bases - base classes and their offsets in the record. - ASTRecordLayout::BaseOffsetsMapTy Bases; - - // 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; - - ASTRecordLayoutBuilder(ASTContext &Ctx); - - void Layout(const RecordDecl *D); - void Layout(const CXXRecordDecl *D); - void Layout(const ObjCInterfaceDecl *D, - const ObjCImplementationDecl *Impl); - - void LayoutFields(const RecordDecl *D); - void LayoutField(const FieldDecl *D); - void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize); - void LayoutBitField(const FieldDecl *D); - - /// 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); - - 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); - - void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, - const CXXRecordDecl *MostDerivedClass); - - /// LayoutVirtualBases - Lays out all the virtual bases. - void LayoutVirtualBases(const CXXRecordDecl *RD, - 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); - - /// canPlaceRecordAtOffset - Return whether a record (either a base class - /// or a field) can be placed at the given offset. - /// Returns false if placing the record will result in two components - /// (direct or indirect) of the same type having the same offset. - bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const; - - /// canPlaceFieldAtOffset - Return whether a field can be placed at the given - /// offset. - bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const; - - /// UpdateEmptyClassOffsets - Called after a record (either a base class - /// or a field) has been placed at the given offset. Will update the - /// EmptyClassOffsets map if the class is empty or has any empty bases or - /// fields. - void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset); - - /// UpdateEmptyClassOffsets - Called after a field has been placed at the - /// given offset. - void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset); - - /// FinishLayout - Finalize record layout. Adjust record size based on the - /// alignment. - void FinishLayout(); - - void UpdateAlignment(unsigned NewAlignment); - - ASTRecordLayoutBuilder(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT - void operator=(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT -public: - static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx, - const RecordDecl *RD); - static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx, - const ObjCInterfaceDecl *D, - const ObjCImplementationDecl *Impl); - static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); -}; - -} // end namespace clang - -#endif - diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 67fd74c288c7..80f5695e42ad 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -27,7 +27,7 @@ static struct StmtClassNameTable { const char *Name; unsigned Counter; unsigned Size; -} StmtClassInfo[Stmt::lastExprConstant+1]; +} StmtClassInfo[Stmt::lastStmtConstant+1]; static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { static bool Initialized = false; @@ -36,11 +36,11 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { // Intialize the table on the first use. Initialized = true; -#define ABSTRACT_EXPR(CLASS, PARENT) +#define ABSTRACT_STMT(STMT) #define STMT(CLASS, PARENT) \ StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \ StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS); -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" return StmtClassInfo[E]; } @@ -55,13 +55,13 @@ void Stmt::PrintStats() { unsigned sum = 0; fprintf(stderr, "*** Stmt/Expr Stats:\n"); - for (int i = 0; i != Stmt::lastExprConstant+1; i++) { + for (int i = 0; i != Stmt::lastStmtConstant+1; i++) { if (StmtClassInfo[i].Name == 0) continue; sum += StmtClassInfo[i].Counter; } fprintf(stderr, " %d stmts/exprs total.\n", sum); sum = 0; - for (int i = 0; i != Stmt::lastExprConstant+1; i++) { + for (int i = 0; i != Stmt::lastStmtConstant+1; i++) { if (StmtClassInfo[i].Name == 0) continue; if (StmtClassInfo[i].Counter == 0) continue; fprintf(stderr, " %d %s, %d each (%d bytes)\n", diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index a11e313fa8ae..b388a3b18ffa 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -66,8 +66,8 @@ namespace { DumpSubTree(*CI++); } } - OS << ')'; } + OS << ')'; } else { Indent(); OS << "<<<NULL>>>"; diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 52f627d449e2..9bef49c3984d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -89,7 +89,7 @@ namespace { void VisitStmt(Stmt *Node); #define STMT(CLASS, PARENT) \ void Visit##CLASS(CLASS *Node); -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" }; } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index d45bb2f010c0..ac3a9eeda66f 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -36,7 +36,7 @@ namespace { void VisitStmt(Stmt *S); #define STMT(Node, Base) void Visit##Node(Node *S); -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" /// \brief Visit a declaration that is referenced within an expression /// or statement. @@ -430,7 +430,215 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) { ID.AddBoolean(S->isConstQualAdded()); } +static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S, + UnaryOperator::Opcode &UnaryOp, + BinaryOperator::Opcode &BinaryOp) { + switch (S->getOperator()) { + case OO_None: + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + case OO_Arrow: + case OO_Call: + case OO_Conditional: + case NUM_OVERLOADED_OPERATORS: + llvm_unreachable("Invalid operator call kind"); + return Stmt::ArraySubscriptExprClass; + + case OO_Plus: + if (S->getNumArgs() == 1) { + UnaryOp = UnaryOperator::Plus; + return Stmt::UnaryOperatorClass; + } + + BinaryOp = BinaryOperator::Add; + return Stmt::BinaryOperatorClass; + + case OO_Minus: + if (S->getNumArgs() == 1) { + UnaryOp = UnaryOperator::Minus; + return Stmt::UnaryOperatorClass; + } + + BinaryOp = BinaryOperator::Sub; + return Stmt::BinaryOperatorClass; + + case OO_Star: + if (S->getNumArgs() == 1) { + UnaryOp = UnaryOperator::Minus; + return Stmt::UnaryOperatorClass; + } + + BinaryOp = BinaryOperator::Sub; + return Stmt::BinaryOperatorClass; + + case OO_Slash: + BinaryOp = BinaryOperator::Div; + return Stmt::BinaryOperatorClass; + + case OO_Percent: + BinaryOp = BinaryOperator::Rem; + return Stmt::BinaryOperatorClass; + + case OO_Caret: + BinaryOp = BinaryOperator::Xor; + return Stmt::BinaryOperatorClass; + + case OO_Amp: + if (S->getNumArgs() == 1) { + UnaryOp = UnaryOperator::AddrOf; + return Stmt::UnaryOperatorClass; + } + + BinaryOp = BinaryOperator::And; + return Stmt::BinaryOperatorClass; + + case OO_Pipe: + BinaryOp = BinaryOperator::Or; + return Stmt::BinaryOperatorClass; + + case OO_Tilde: + UnaryOp = UnaryOperator::Not; + return Stmt::UnaryOperatorClass; + + case OO_Exclaim: + UnaryOp = UnaryOperator::LNot; + return Stmt::UnaryOperatorClass; + + case OO_Equal: + BinaryOp = BinaryOperator::Assign; + return Stmt::BinaryOperatorClass; + + case OO_Less: + BinaryOp = BinaryOperator::LT; + return Stmt::BinaryOperatorClass; + + case OO_Greater: + BinaryOp = BinaryOperator::GT; + return Stmt::BinaryOperatorClass; + + case OO_PlusEqual: + BinaryOp = BinaryOperator::AddAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_MinusEqual: + BinaryOp = BinaryOperator::SubAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_StarEqual: + BinaryOp = BinaryOperator::MulAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_SlashEqual: + BinaryOp = BinaryOperator::DivAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_PercentEqual: + BinaryOp = BinaryOperator::RemAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_CaretEqual: + BinaryOp = BinaryOperator::XorAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_AmpEqual: + BinaryOp = BinaryOperator::AndAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_PipeEqual: + BinaryOp = BinaryOperator::OrAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_LessLess: + BinaryOp = BinaryOperator::Shl; + return Stmt::BinaryOperatorClass; + + case OO_GreaterGreater: + BinaryOp = BinaryOperator::Shr; + return Stmt::BinaryOperatorClass; + + case OO_LessLessEqual: + BinaryOp = BinaryOperator::ShlAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_GreaterGreaterEqual: + BinaryOp = BinaryOperator::ShrAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_EqualEqual: + BinaryOp = BinaryOperator::EQ; + return Stmt::BinaryOperatorClass; + + case OO_ExclaimEqual: + BinaryOp = BinaryOperator::NE; + return Stmt::BinaryOperatorClass; + + case OO_LessEqual: + BinaryOp = BinaryOperator::LE; + return Stmt::BinaryOperatorClass; + + case OO_GreaterEqual: + BinaryOp = BinaryOperator::GE; + return Stmt::BinaryOperatorClass; + + case OO_AmpAmp: + BinaryOp = BinaryOperator::LAnd; + return Stmt::BinaryOperatorClass; + + case OO_PipePipe: + BinaryOp = BinaryOperator::LOr; + return Stmt::BinaryOperatorClass; + + case OO_PlusPlus: + UnaryOp = S->getNumArgs() == 1? UnaryOperator::PreInc + : UnaryOperator::PostInc; + return Stmt::UnaryOperatorClass; + + case OO_MinusMinus: + UnaryOp = S->getNumArgs() == 1? UnaryOperator::PreDec + : UnaryOperator::PostDec; + return Stmt::UnaryOperatorClass; + + case OO_Comma: + BinaryOp = BinaryOperator::Comma; + return Stmt::BinaryOperatorClass; + + + case OO_ArrowStar: + BinaryOp = BinaryOperator::PtrMemI; + return Stmt::BinaryOperatorClass; + + case OO_Subscript: + return Stmt::ArraySubscriptExprClass; + } + + llvm_unreachable("Invalid overloaded operator expression"); +} + + void StmtProfiler::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *S) { + if (S->isTypeDependent()) { + // Type-dependent operator calls are profiled like their underlying + // syntactic operator. + UnaryOperator::Opcode UnaryOp = UnaryOperator::Extension; + BinaryOperator::Opcode BinaryOp = BinaryOperator::Comma; + Stmt::StmtClass SC = DecodeOperatorCall(S, UnaryOp, BinaryOp); + + ID.AddInteger(SC); + for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I) + Visit(S->getArg(I)); + if (SC == Stmt::UnaryOperatorClass) + ID.AddInteger(UnaryOp); + else if (SC == Stmt::BinaryOperatorClass || + SC == Stmt::CompoundAssignOperatorClass) + ID.AddInteger(BinaryOp); + else + assert(SC == Stmt::ArraySubscriptExprClass); + + return; + } + VisitCallExpr(S); ID.AddInteger(S->getOperator()); } diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index e9b17256415f..1c775efe5777 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/Diagnostic.h" using namespace clang; @@ -102,7 +103,7 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { return getSourceDeclExpression()->getSourceRange(); case TemplateArgument::Type: - return getTypeSourceInfo()->getTypeLoc().getFullSourceRange(); + return getTypeSourceInfo()->getTypeLoc().getSourceRange(); case TemplateArgument::Template: if (getTemplateQualifierRange().isValid()) @@ -119,3 +120,42 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { // Silence bonus gcc warning. return SourceRange(); } + +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + return DB; + + case TemplateArgument::Type: + return DB << Arg.getAsType(); + + case TemplateArgument::Declaration: + return DB << Arg.getAsDecl(); + + case TemplateArgument::Integral: + return DB << Arg.getAsIntegral()->toString(10); + + case TemplateArgument::Template: + return DB << Arg.getAsTemplate(); + + case TemplateArgument::Expression: { + // This shouldn't actually ever happen, so it's okay that we're + // regurgitating an expression here. + // FIXME: We're guessing at LangOptions! + llvm::SmallString<32> Str; + llvm::raw_svector_ostream OS(Str); + LangOptions LangOpts; + LangOpts.CPlusPlus = true; + PrintingPolicy Policy(LangOpts); + Arg.getAsExpr()->printPretty(OS, 0, Policy); + return DB << OS.str(); + } + + case TemplateArgument::Pack: + // FIXME: Format arguments in a list! + return DB << "<parameter pack>"; + } + + return DB; +} diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 05e7fdc49e35..1aab65ebec55 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/Specifiers.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -276,6 +277,9 @@ QualType Type::getPointeeType() const { /// array types and types that contain variable array types in their /// declarator bool Type::isVariablyModifiedType() const { + // FIXME: We should really keep a "variably modified" bit in Type, rather + // than walking the type hierarchy to recompute it. + // A VLA is a variably modified type. if (isVariableArrayType()) return true; @@ -344,29 +348,36 @@ const RecordType *Type::getAsUnionType() const { return 0; } -ObjCInterfaceType::ObjCInterfaceType(QualType Canonical, - ObjCInterfaceDecl *D, - ObjCProtocolDecl **Protos, unsigned NumP) : - Type(ObjCInterface, Canonical, /*Dependent=*/false), - Decl(D), NumProtocols(NumP) -{ +void ObjCInterfaceType::Destroy(ASTContext& C) { + this->~ObjCInterfaceType(); + C.Deallocate(this); +} + +ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) + : Type(ObjCObject, Canonical, false), + NumProtocols(NumProtocols), + BaseType(Base) { + assert(this->NumProtocols == NumProtocols && + "bitfield overflow in protocol count"); if (NumProtocols) - memcpy(reinterpret_cast<ObjCProtocolDecl**>(this + 1), Protos, - NumProtocols * sizeof(*Protos)); + memcpy(getProtocolStorage(), Protocols, + NumProtocols * sizeof(ObjCProtocolDecl*)); } -void ObjCInterfaceType::Destroy(ASTContext& C) { - this->~ObjCInterfaceType(); +void ObjCObjectTypeImpl::Destroy(ASTContext& C) { + this->~ObjCObjectTypeImpl(); C.Deallocate(this); } -const ObjCInterfaceType *Type::getAsObjCQualifiedInterfaceType() const { - // There is no sugar for ObjCInterfaceType's, just return the canonical +const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { + // There is no sugar for ObjCObjectType's, just return the canonical // type pointer if it is the right class. There is no typedef information to // return and these cannot be Address-space qualified. - if (const ObjCInterfaceType *OIT = getAs<ObjCInterfaceType>()) - if (OIT->getNumProtocols()) - return OIT; + if (const ObjCObjectType *T = getAs<ObjCObjectType>()) + if (T->getNumProtocols() && T->getInterface()) + return T; return 0; } @@ -374,17 +385,6 @@ bool Type::isObjCQualifiedInterfaceType() const { return getAsObjCQualifiedInterfaceType() != 0; } -ObjCObjectPointerType::ObjCObjectPointerType(QualType Canonical, QualType T, - ObjCProtocolDecl **Protos, - unsigned NumP) : - Type(ObjCObjectPointer, Canonical, /*Dependent=*/false), - PointeeType(T), NumProtocols(NumP) -{ - if (NumProtocols) - memcpy(reinterpret_cast<ObjCProtocolDecl **>(this + 1), Protos, - NumProtocols * sizeof(*Protos)); -} - void ObjCObjectPointerType::Destroy(ASTContext& C) { this->~ObjCObjectPointerType(); C.Deallocate(this); @@ -637,6 +637,8 @@ bool Type::isIncompleteType() const { case IncompleteArray: // An array of unknown size is an incomplete type (C99 6.2.5p22). return true; + case ObjCObject: + return cast<ObjCObjectType>(this)->getBaseType()->isIncompleteType(); case ObjCInterface: // ObjC interfaces are incomplete if they are @class, not @interface. return cast<ObjCInterfaceType>(this)->getDecl()->isForwardDecl(); @@ -764,36 +766,106 @@ bool Type::isSpecifierType() const { case TemplateTypeParm: case SubstTemplateTypeParm: case TemplateSpecialization: - case QualifiedName: + case Elaborated: case DependentName: case ObjCInterface: - case ObjCObjectPointer: - case Elaborated: + case ObjCObject: + case ObjCObjectPointer: // FIXME: object pointers aren't really specifiers return true; default: return false; } } -bool Type::isElaboratedTypeSpecifier() const { - if (getTypeClass() == Elaborated) +TypeWithKeyword::~TypeWithKeyword() { +} + +ElaboratedTypeKeyword +TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { + switch (TypeSpec) { + default: return ETK_None; + case TST_typename: return ETK_Typename; + case TST_class: return ETK_Class; + case TST_struct: return ETK_Struct; + case TST_union: return ETK_Union; + case TST_enum: return ETK_Enum; + } +} + +TagTypeKind +TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { + switch(TypeSpec) { + case TST_class: return TTK_Class; + case TST_struct: return TTK_Struct; + case TST_union: return TTK_Union; + case TST_enum: return TTK_Enum; + default: llvm_unreachable("Type specifier is not a tag type kind."); + } +} + +ElaboratedTypeKeyword +TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { + switch (Kind) { + case TTK_Class: return ETK_Class; + case TTK_Struct: return ETK_Struct; + case TTK_Union: return ETK_Union; + case TTK_Enum: return ETK_Enum; + } + llvm_unreachable("Unknown tag type kind."); +} + +TagTypeKind +TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { + switch (Keyword) { + case ETK_Class: return TTK_Class; + case ETK_Struct: return TTK_Struct; + case ETK_Union: return TTK_Union; + case ETK_Enum: return TTK_Enum; + case ETK_None: // Fall through. + case ETK_Typename: + llvm_unreachable("Elaborated type keyword is not a tag type kind."); + } + llvm_unreachable("Unknown elaborated type keyword."); +} + +bool +TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { + switch (Keyword) { + case ETK_None: + case ETK_Typename: + return false; + case ETK_Class: + case ETK_Struct: + case ETK_Union: + case ETK_Enum: return true; - - if (const DependentNameType *Dependent = dyn_cast<DependentNameType>(this)) { - switch (Dependent->getKeyword()) { - case ETK_None: - case ETK_Typename: - return false; - - case ETK_Class: - case ETK_Struct: - case ETK_Union: - case ETK_Enum: - return true; - } } - - return false; + llvm_unreachable("Unknown elaborated type keyword."); +} + +const char* +TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { + switch (Keyword) { + default: llvm_unreachable("Unknown elaborated type keyword."); + case ETK_None: return ""; + case ETK_Typename: return "typename"; + case ETK_Class: return "class"; + case ETK_Struct: return "struct"; + case ETK_Union: return "union"; + case ETK_Enum: return "enum"; + } +} + +bool Type::isElaboratedTypeSpecifier() const { + ElaboratedTypeKeyword Keyword; + if (const ElaboratedType *Elab = dyn_cast<ElaboratedType>(this)) + Keyword = Elab->getKeyword(); + else if (const DependentNameType *DepName = dyn_cast<DependentNameType>(this)) + Keyword = DepName->getKeyword(); + else + return false; + + return TypeWithKeyword::KeywordIsTagTypeKind(Keyword); } const char *Type::getTypeClassName() const { @@ -836,10 +908,12 @@ const char *BuiltinType::getName(const LangOptions &LO) const { case UndeducedAuto: return "auto"; case ObjCId: return "id"; case ObjCClass: return "Class"; - case ObjCSel: return "SEL"; + case ObjCSel: return "SEL"; } } +void FunctionType::ANCHOR() {} // Key function for FunctionType. + llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { switch (CC) { case CC_Default: llvm_unreachable("no name for default cc"); @@ -848,6 +922,7 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_C: return "cdecl"; case CC_X86StdCall: return "stdcall"; case CC_X86FastCall: return "fastcall"; + case CC_X86ThisCall: return "thiscall"; } } @@ -881,19 +956,6 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { getExtInfo()); } -void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID, - QualType OIT, - ObjCProtocolDecl * const *protocols, - unsigned NumProtocols) { - ID.AddPointer(OIT.getAsOpaquePtr()); - for (unsigned i = 0; i != NumProtocols; i++) - ID.AddPointer(protocols[i]); -} - -void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getPointeeType(), qual_begin(), getNumProtocols()); -} - /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to /// potentially looking through *all* consequtive typedefs. This returns the /// sum of the type qualifiers, so if you have: @@ -975,6 +1037,10 @@ static bool isDependent(const TemplateArgument &Arg) { return Arg.getAsTemplate().isDependent(); case TemplateArgument::Declaration: + if (DeclContext *DC = dyn_cast<DeclContext>(Arg.getAsDecl())) + return DC->isDependentContext(); + return Arg.getAsDecl()->getDeclContext()->isDependentContext(); + case TemplateArgument::Integral: // Never dependent return false; @@ -984,7 +1050,13 @@ static bool isDependent(const TemplateArgument &Arg) { Arg.getAsExpr()->isValueDependent()); case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); + for (TemplateArgument::pack_iterator P = Arg.pack_begin(), + PEnd = Arg.pack_end(); + P != PEnd; ++P) { + if (isDependent(*P)) + return true; + } + return false; } @@ -1081,36 +1153,53 @@ QualType QualifierCollector::apply(const Type *T) const { return Context->getQualifiedType(T, *this); } -void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl * const *protocols, - unsigned NumProtocols) { - ID.AddPointer(Decl); +void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID, + QualType BaseType, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) { + ID.AddPointer(BaseType.getAsOpaquePtr()); for (unsigned i = 0; i != NumProtocols; i++) - ID.AddPointer(protocols[i]); + ID.AddPointer(Protocols[i]); } -void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDecl(), qual_begin(), getNumProtocols()); +void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getBaseType(), qual_begin(), getNumProtocols()); } -Linkage Type::getLinkage() const { - // C++ [basic.link]p8: - // Names not covered by these rules have no linkage. +/// \brief Determine the linkage of this type. +Linkage Type::getLinkage() const { if (this != CanonicalType.getTypePtr()) return CanonicalType->getLinkage(); + + if (!LinkageKnown) { + CachedLinkage = getLinkageImpl(); + LinkageKnown = true; + } + + return static_cast<clang::Linkage>(CachedLinkage); +} +Linkage Type::getLinkageImpl() const { + // C++ [basic.link]p8: + // Names not covered by these rules have no linkage. return NoLinkage; } -Linkage BuiltinType::getLinkage() const { +void Type::ClearLinkageCache() { + if (this != CanonicalType.getTypePtr()) + CanonicalType->ClearLinkageCache(); + else + LinkageKnown = false; +} + +Linkage BuiltinType::getLinkageImpl() const { // C++ [basic.link]p8: // A type is said to have linkage if and only if: // - it is a fundamental type (3.9.1); or return ExternalLinkage; } -Linkage TagType::getLinkage() const { +Linkage TagType::getLinkageImpl() const { // C++ [basic.link]p8: // - it is a class or enumeration type that is named (or has a name for // linkage purposes (7.1.3)) and the name has linkage; or @@ -1121,39 +1210,39 @@ Linkage TagType::getLinkage() const { // C++ [basic.link]p8: // - it is a compound type (3.9.2) other than a class or enumeration, // compounded exclusively from types that have linkage; or -Linkage ComplexType::getLinkage() const { +Linkage ComplexType::getLinkageImpl() const { return ElementType->getLinkage(); } -Linkage PointerType::getLinkage() const { +Linkage PointerType::getLinkageImpl() const { return PointeeType->getLinkage(); } -Linkage BlockPointerType::getLinkage() const { +Linkage BlockPointerType::getLinkageImpl() const { return PointeeType->getLinkage(); } -Linkage ReferenceType::getLinkage() const { +Linkage ReferenceType::getLinkageImpl() const { return PointeeType->getLinkage(); } -Linkage MemberPointerType::getLinkage() const { +Linkage MemberPointerType::getLinkageImpl() const { return minLinkage(Class->getLinkage(), PointeeType->getLinkage()); } -Linkage ArrayType::getLinkage() const { +Linkage ArrayType::getLinkageImpl() const { return ElementType->getLinkage(); } -Linkage VectorType::getLinkage() const { +Linkage VectorType::getLinkageImpl() const { return ElementType->getLinkage(); } -Linkage FunctionNoProtoType::getLinkage() const { +Linkage FunctionNoProtoType::getLinkageImpl() const { return getResultType()->getLinkage(); } -Linkage FunctionProtoType::getLinkage() const { +Linkage FunctionProtoType::getLinkageImpl() const { Linkage L = getResultType()->getLinkage(); for (arg_type_iterator A = arg_type_begin(), AEnd = arg_type_end(); A != AEnd; ++A) @@ -1162,10 +1251,10 @@ Linkage FunctionProtoType::getLinkage() const { return L; } -Linkage ObjCInterfaceType::getLinkage() const { +Linkage ObjCObjectType::getLinkageImpl() const { return ExternalLinkage; } -Linkage ObjCObjectPointerType::getLinkage() const { +Linkage ObjCObjectPointerType::getLinkageImpl() const { return ExternalLinkage; } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index fd9fbc191868..4893b384dd10 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -27,13 +27,13 @@ namespace { #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return TyLoc.getSourceRange(); \ + return TyLoc.getLocalSourceRange(); \ } #include "clang/AST/TypeLocNodes.def" }; } -SourceRange TypeLoc::getSourceRangeImpl(TypeLoc TL) { +SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) { if (TL.isNull()) return SourceRange(); return TypeLocRanger().Visit(TL); } @@ -92,11 +92,58 @@ namespace { /// recursively, as if the entire tree had been written in the /// given location. void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) { - do { - TypeLocInitializer(Loc).Visit(TL); - } while ((TL = TL.getNextTypeLoc())); + while (true) { + switch (TL.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case CLASS: { \ + CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \ + TLCasted.initializeLocal(Loc); \ + TL = TLCasted.getNextTypeLoc(); \ + if (!TL) return; \ + continue; \ + } +#include "clang/AST/TypeLocNodes.def" + } + } +} + +SourceLocation TypeLoc::getBeginLoc() const { + TypeLoc Cur = *this; + while (true) { + switch (Cur.getTypeLocClass()) { + // FIXME: Currently QualifiedTypeLoc does not have a source range + // case Qualified: + case Elaborated: + break; + default: + TypeLoc Next = Cur.getNextTypeLoc(); + if (Next.isNull()) break; + Cur = Next; + continue; + } + break; + } + return Cur.getLocalSourceRange().getBegin(); } +SourceLocation TypeLoc::getEndLoc() const { + TypeLoc Cur = *this; + while (true) { + switch (Cur.getTypeLocClass()) { + default: + break; + case Qualified: + case Elaborated: + Cur = Cur.getNextTypeLoc(); + continue; + } + break; + } + return Cur.getLocalSourceRange().getEnd(); +} + + namespace { struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> { // Overload resolution does the real work for us. @@ -129,7 +176,7 @@ bool TypeSpecTypeLoc::classof(const TypeLoc *TL) { // Reimplemented to account for GNU/C++ extension // typeof unary-expression // where there are no parentheses. -SourceRange TypeOfExprTypeLoc::getSourceRange() const { +SourceRange TypeOfExprTypeLoc::getLocalSourceRange() const { if (getRParenLoc().isValid()) return SourceRange(getTypeofLoc(), getRParenLoc()); else diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 915d7af9a8c3..35a7e096994d 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -295,6 +295,9 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, case CC_X86FastCall: S += " __attribute__((fastcall))"; break; + case CC_X86ThisCall: + S += " __attribute__((thiscall))"; + break; } if (Info.getNoReturn()) S += " __attribute__((noreturn))"; @@ -497,16 +500,6 @@ void TypePrinter::PrintEnum(const EnumType *T, std::string &S) { PrintTag(T->getDecl(), S); } -void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) { - Print(T->getUnderlyingType(), 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, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'. @@ -549,13 +542,17 @@ void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T, PrintTemplateSpecialization(T->getInjectedTST(), S); } -void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, - std::string &S) { +void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) { std::string MyString; { llvm::raw_string_ostream OS(MyString); - T->getQualifier()->print(OS, Policy); + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ETK_None) + OS << " "; + NestedNameSpecifier* Qualifier = T->getQualifier(); + if (Qualifier) + Qualifier->print(OS, Policy); } std::string TypeStr; @@ -575,14 +572,9 @@ void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S) { llvm::raw_string_ostream OS(MyString); - switch (T->getKeyword()) { - case ETK_None: break; - case ETK_Typename: OS << "typename "; break; - case ETK_Class: OS << "class "; break; - case ETK_Struct: OS << "struct "; break; - case ETK_Union: OS << "union "; break; - case ETK_Enum: OS << "enum "; break; - } + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ETK_None) + OS << " "; T->getQualifier()->print(OS, Policy); @@ -607,25 +599,37 @@ void TypePrinter::PrintObjCInterface(const ObjCInterfaceType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. S = ' ' + S; - + std::string ObjCQIString = T->getDecl()->getNameAsString(); - if (T->getNumProtocols()) { - ObjCQIString += '<'; - bool isFirst = true; - for (ObjCInterfaceType::qual_iterator I = T->qual_begin(), - E = T->qual_end(); - I != E; ++I) { - if (isFirst) - isFirst = false; - else - ObjCQIString += ','; - ObjCQIString += (*I)->getNameAsString(); - } - ObjCQIString += '>'; - } S = ObjCQIString + S; } +void TypePrinter::PrintObjCObject(const ObjCObjectType *T, + std::string &S) { + if (T->qual_empty()) + return Print(T->getBaseType(), S); + + std::string tmp; + Print(T->getBaseType(), tmp); + tmp += '<'; + bool isFirst = true; + for (ObjCObjectType::qual_iterator + I = T->qual_begin(), E = T->qual_end(); I != E; ++I) { + if (isFirst) + isFirst = false; + else + tmp += ','; + tmp += (*I)->getNameAsString(); + } + tmp += '>'; + + if (!S.empty()) { + tmp += ' '; + tmp += S; + } + std::swap(tmp, S); +} + void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T, std::string &S) { std::string ObjCQIString; diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 7f71e0acf7a3..6f2cb41a6e40 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -985,6 +985,11 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { } else LoopSuccessor = Succ; + // Save the current value for the break targets. + // All breaks should go to the code following the loop. + SaveAndRestore<CFGBlock*> save_break(BreakTargetBlock); + BreakTargetBlock = LoopSuccessor; + // Because of short-circuit evaluation, the condition of the loop can span // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that // evaluate the condition. @@ -1032,10 +1037,9 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { { assert(F->getBody()); - // Save the current values for Block, Succ, and continue and break targets - SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ), - save_continue(ContinueTargetBlock), - save_break(BreakTargetBlock); + // Save the current values for Block, Succ, and continue targets. + SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock); // Create a new block to contain the (bottom) of the loop body. Block = NULL; @@ -1065,9 +1069,6 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { // represent the 'loop target' for looping back to the start of the loop. ContinueTargetBlock->setLoopTarget(F); - // All breaks should go to the code following the loop. - BreakTargetBlock = LoopSuccessor; - // Now populate the body block, and in the process create new blocks as we // walk the body of the loop. CFGBlock* BodyBlock = addStmt(F->getBody()); @@ -1223,10 +1224,9 @@ CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) { return 0; Block = 0; + Succ = SyncBlock; } - Succ = SyncBlock; - // Inline the sync expression. return addStmt(S->getSynchExpr()); } diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index b4e0e242485b..a8e37087c09c 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -9,4 +9,4 @@ add_clang_library(clangAnalysis UninitializedValues.cpp ) -add_dependencies(clangAnalysis ClangDiagnosticAnalysis) +add_dependencies(clangAnalysis ClangDiagnosticAnalysis ClangStmtNodes) diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 9e6f168f1711..2fd985f53803 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -127,6 +127,35 @@ const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) { return 0; } +/// getWarningOptionForDiag - Return the category number that a specified +/// DiagID belongs to, or 0 if no category. +unsigned Diagnostic::getCategoryNumberForDiag(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Category; + return 0; +} + +/// getCategoryNameFromID - Given a category ID, return the name of the +/// category, an empty string if CategoryID is zero, or null if CategoryID is +/// invalid. +const char *Diagnostic::getCategoryNameFromID(unsigned CategoryID) { + // Second the table of options, sorted by name for fast binary lookup. + static const char *CategoryNameTable[] = { +#define GET_CATEGORY_TABLE +#define CATEGORY(X) X, +#include "clang/Basic/DiagnosticGroups.inc" +#undef GET_CATEGORY_TABLE + "<<END>>" + }; + static const size_t CategoryNameTableSize = + sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1; + + if (CategoryID >= CategoryNameTableSize) return 0; + return CategoryNameTable[CategoryID]; +} + + + Diagnostic::SFINAEResponse Diagnostic::getDiagnosticSFINAEResponse(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) { @@ -432,7 +461,7 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { struct WarningOption { const char *Name; const short *Members; - const char *SubGroups; + const short *SubGroups; }; #define GET_DIAG_ARRAYS @@ -462,9 +491,9 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping, } // Enable/disable all subgroups along with this one. - if (const char *SubGroups = Group->SubGroups) { - for (; *SubGroups != (char)-1; ++SubGroups) - MapGroupMembers(&OptionTable[(unsigned char)*SubGroups], Mapping, Diags); + if (const short *SubGroups = Group->SubGroups) { + for (; *SubGroups != (short)-1; ++SubGroups) + MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Diags); } } diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index ed0de8c4af09..8993e6713fbe 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -70,7 +70,8 @@ namespace { KEYGNU = 16, KEYMS = 32, BOOLSUPPORT = 64, - KEYALTIVEC = 128 + KEYALTIVEC = 128, + KEYNOMS = 256 }; } @@ -94,6 +95,7 @@ static void AddKeyword(llvm::StringRef Keyword, else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1; else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2; else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; + else if (!LangOpts.Microsoft && (Flags & KEYNOMS)) AddResult = 2; // Don't add this keyword if disabled in this language. if (AddResult == 0) return; diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 3ecab1d8c16f..e6d9785e1505 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -1154,6 +1154,27 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1); } +/// Given a decomposed source location, move it up the include/instantiation +/// stack to the parent source location. If this is possible, return the +/// decomposed version of the parent in Loc and return false. If Loc is the +/// top-level entry, return true and don't modify it. +static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc, + const SourceManager &SM) { + SourceLocation UpperLoc; + const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(Loc.first); + if (Entry.isInstantiation()) + UpperLoc = Entry.getInstantiation().getInstantiationLocStart(); + else + UpperLoc = Entry.getFile().getIncludeLoc(); + + if (UpperLoc.isInvalid()) + return true; // We reached the top. + + Loc = SM.getDecomposedLoc(UpperLoc); + return false; +} + + /// \brief Determines the order of 2 source locations in the translation unit. /// /// \returns true if LHS source location comes before RHS, false otherwise. @@ -1172,78 +1193,74 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, // If we are comparing a source location with multiple locations in the same // file, we get a big win by caching the result. + if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first)) + return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second); - if (LastLFIDForBeforeTUCheck == LOffs.first && - LastRFIDForBeforeTUCheck == ROffs.first) - return LastResForBeforeTUCheck; - - LastLFIDForBeforeTUCheck = LOffs.first; - LastRFIDForBeforeTUCheck = ROffs.first; + // Okay, we missed in the cache, start updating the cache for this query. + IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first); // "Traverse" the include/instantiation stacks of both locations and try to - // find a common "ancestor". + // find a common "ancestor". FileIDs build a tree-like structure that + // reflects the #include hierarchy, and this algorithm needs to find the + // nearest common ancestor between the two locations. For example, if you + // have a.c that includes b.h and c.h, and are comparing a location in b.h to + // a location in c.h, we need to find that their nearest common ancestor is + // a.c, and compare the locations of the two #includes to find their relative + // ordering. // - // First we traverse the stack of the right location and check each level - // against the level of the left location, while collecting all levels in a - // "stack map". - - std::map<FileID, unsigned> ROffsMap; - ROffsMap[ROffs.first] = ROffs.second; - - while (1) { - SourceLocation UpperLoc; - const SrcMgr::SLocEntry &Entry = getSLocEntry(ROffs.first); - if (Entry.isInstantiation()) - UpperLoc = Entry.getInstantiation().getInstantiationLocStart(); - else - UpperLoc = Entry.getFile().getIncludeLoc(); - - if (UpperLoc.isInvalid()) - break; // We reached the top. - - ROffs = getDecomposedLoc(UpperLoc); - - if (LOffs.first == ROffs.first) - return LastResForBeforeTUCheck = LOffs.second < ROffs.second; - - ROffsMap[ROffs.first] = ROffs.second; - } - - // We didn't find a common ancestor. Now traverse the stack of the left - // location, checking against the stack map of the right location. - - while (1) { - SourceLocation UpperLoc; - const SrcMgr::SLocEntry &Entry = getSLocEntry(LOffs.first); - if (Entry.isInstantiation()) - UpperLoc = Entry.getInstantiation().getInstantiationLocStart(); - else - UpperLoc = Entry.getFile().getIncludeLoc(); - - if (UpperLoc.isInvalid()) - break; // We reached the top. - - LOffs = getDecomposedLoc(UpperLoc); + // SourceManager assigns FileIDs in order of parsing. This means that an + // includee always has a larger FileID than an includer. While you might + // think that we could just compare the FileID's here, that doesn't work to + // compare a point at the end of a.c with a point within c.h. Though c.h has + // a larger FileID, we have to compare the include point of c.h to the + // location in a.c. + // + // Despite not being able to directly compare FileID's, we can tell that a + // larger FileID is necessarily more deeply nested than a lower one and use + // this information to walk up the tree to the nearest common ancestor. + do { + // If LOffs is larger than ROffs, then LOffs must be more deeply nested than + // ROffs, walk up the #include chain. + if (LOffs.first.ID > ROffs.first.ID) { + if (MoveUpIncludeHierarchy(LOffs, *this)) + break; // We reached the top. + + } else { + // Otherwise, ROffs is larger than LOffs, so ROffs must be more deeply + // nested than LOffs, walk up the #include chain. + if (MoveUpIncludeHierarchy(ROffs, *this)) + break; // We reached the top. + } + } while (LOffs.first != ROffs.first); - std::map<FileID, unsigned>::iterator I = ROffsMap.find(LOffs.first); - if (I != ROffsMap.end()) - return LastResForBeforeTUCheck = LOffs.second < I->second; + // If we exited because we found a nearest common ancestor, compare the + // locations within the common file and cache them. + if (LOffs.first == ROffs.first) { + IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second); + return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second); } // There is no common ancestor, most probably because one location is in the - // predefines buffer. - // + // predefines buffer or a PCH file. // FIXME: We should rearrange the external interface so this simply never // happens; it can't conceptually happen. Also see PR5662. + IsBeforeInTUCache.setQueryFIDs(FileID(), FileID()); // Don't try caching. + // Zip both entries up to the top level record. + while (!MoveUpIncludeHierarchy(LOffs, *this)) /*empty*/; + while (!MoveUpIncludeHierarchy(ROffs, *this)) /*empty*/; + // If exactly one location is a memory buffer, assume it preceeds the other. - bool LIsMB = !getSLocEntry(LOffs.first).getFile().getContentCache()->Entry; - bool RIsMB = !getSLocEntry(ROffs.first).getFile().getContentCache()->Entry; + + // Strip off macro instantation locations, going up to the top-level File + // SLocEntry. + bool LIsMB = getFileEntryForID(LOffs.first) == 0; + bool RIsMB = getFileEntryForID(ROffs.first) == 0; if (LIsMB != RIsMB) - return LastResForBeforeTUCheck = LIsMB; + return LIsMB; // Otherwise, just assume FileIDs were created in order. - return LastResForBeforeTUCheck = (LOffs.first < ROffs.first); + return LOffs.first < ROffs.first; } /// PrintStats - Print statistics to stderr. diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 4c0c59a109e7..6692e641f2a4 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -52,6 +52,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-n32"; UserLabelPrefix = "_"; + HasAlignMac68kSupport = false; } // Out of line virtual dtor for TargetInfo. diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 3d5048ccb9bf..92fd417173bd 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -1138,6 +1138,7 @@ public: DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" "a0:0:64-f80:128:128-n8:16:32"; + HasAlignMac68kSupport = true; } }; @@ -1669,7 +1670,9 @@ protected: public: DarwinARMTargetInfo(const std::string& triple) - : DarwinTargetInfo<ARMTargetInfo>(triple) {} + : DarwinTargetInfo<ARMTargetInfo>(triple) { + HasAlignMac68kSupport = true; + } }; } // end anonymous namespace. diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index dc87d148ed34..e0c23362b930 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -28,7 +28,8 @@ llvm::StringRef getClangRepositoryPath() { if (End) URLEnd = End; - End = strstr(URL, "/clang/tools/clang"); + // Strip off version from a build from an integration branch. + End = strstr(URL, "/src/tools/clang"); if (End) URLEnd = End; diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp index e7275ca551c2..b852e2ad9a48 100644 --- a/lib/Checker/BasicObjCFoundationChecks.cpp +++ b/lib/Checker/BasicObjCFoundationChecks.cpp @@ -521,11 +521,11 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, ObjCInterfaceDecl *Class = 0; switch (ME->getReceiverKind()) { case ObjCMessageExpr::Class: - Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); break; case ObjCMessageExpr::SuperClass: - Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); + Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface(); break; case ObjCMessageExpr::Instance: diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp index 34470af29f4a..5be5ca615ed6 100644 --- a/lib/Checker/BasicStore.cpp +++ b/lib/Checker/BasicStore.cpp @@ -72,7 +72,7 @@ public: /// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values. /// It updatees the GRState object in place with the values removed. - Store RemoveDeadBindings(Store store, Stmt* Loc, + const GRState *RemoveDeadBindings(GRState &state, Stmt* Loc, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); @@ -251,11 +251,12 @@ Store BasicStoreManager::Remove(Store store, Loc loc) { } } -Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, +const GRState *BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) { + Store store = state.getStore(); BindingsTy B = GetBindings(store); typedef SVal::symbol_iterator symbol_iterator; @@ -329,7 +330,8 @@ Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, } } - return store; + state.setStore(store); + return StateMgr.getPersistentState(state); } Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp index d26ee1db5653..42e6f67f0172 100644 --- a/lib/Checker/CFRefCount.cpp +++ b/lib/Checker/CFRefCount.cpp @@ -37,6 +37,49 @@ using namespace clang; using llvm::StringRef; using llvm::StrInStrNoCase; +namespace { +class InstanceReceiver { + const ObjCMessageExpr *ME; + const LocationContext *LC; +public: + InstanceReceiver(const ObjCMessageExpr *me = 0, + const LocationContext *lc = 0) : ME(me), LC(lc) {} + + bool isValid() const { + return ME && ME->isInstanceMessage(); + } + operator bool() const { + return isValid(); + } + + SVal getSValAsScalarOrLoc(const GRState *state) { + assert(isValid()); + // We have an expression for the receiver? Fetch the value + // of that expression. + if (const Expr *Ex = ME->getInstanceReceiver()) + return state->getSValAsScalarOrLoc(Ex); + + // Otherwise we are sending a message to super. In this case the + // object reference is the same as 'self'. + if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) + return state->getSVal(state->getRegion(SelfDecl, LC)); + + return UnknownVal(); + } + + SourceRange getSourceRange() const { + assert(isValid()); + if (const Expr *Ex = ME->getInstanceReceiver()) + return Ex->getSourceRange(); + + // Otherwise we are sending a message to super. + SourceLocation L = ME->getSuperLoc(); + assert(L.isValid()); + return SourceRange(L, L); + } +}; +} + static const ObjCMethodDecl* ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { ObjCInterfaceDecl *ID = @@ -618,11 +661,11 @@ public: break; case ObjCMessageExpr::Class: - OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + OD = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); break; case ObjCMessageExpr::SuperClass: - OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); + OD = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface(); break; } @@ -1374,7 +1417,7 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME, // we just use the 'ID' from the message expression. SVal receiverV; - if (const Expr *Receiver = ME->getInstanceReceiver()) { + if (Receiver) { receiverV = state->getSValAsScalarOrLoc(Receiver); // FIXME: Eventually replace the use of state->get<RefBindings> with @@ -1724,7 +1767,7 @@ private: void ProcessNonLeakError(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, - Expr* NodeExpr, Expr* ErrorExpr, + Expr* NodeExpr, SourceRange ErrorRange, ExplodedNode* Pred, const GRState* St, RefVal::Kind hasErr, SymbolRef Sym); @@ -1768,7 +1811,7 @@ public: GRExprEngine& Eng, GRStmtNodeBuilder& Builder, Expr* Ex, - Expr* Receiver, + InstanceReceiver Receiver, const RetainSummary& Summ, const MemRegion *Callee, ExprIterator arg_beg, ExprIterator arg_end, @@ -2552,7 +2595,8 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { // is a call to a class method whose type we can resolve. In such // cases, promote the return type to XXX* (where XXX is the class). const ObjCInterfaceDecl *D = ME->getReceiverInterface(); - return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); + return !D ? RetTy : + Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D)); } return RetTy; @@ -2562,7 +2606,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, Expr* Ex, - Expr* Receiver, + InstanceReceiver Receiver, const RetainSummary& Summ, const MemRegion *Callee, ExprIterator arg_beg, ExprIterator arg_end, @@ -2571,7 +2615,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, // Evaluate the effect of the arguments. RefVal::Kind hasErr = (RefVal::Kind) 0; unsigned idx = 0; - Expr* ErrorExpr = NULL; + SourceRange ErrorRange; SymbolRef ErrorSym = 0; llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate; @@ -2584,7 +2628,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, if (RefBindings::data_type* T = state->get<RefBindings>(Sym)) { state = Update(state, Sym, *T, Summ.getArg(idx), hasErr); if (hasErr) { - ErrorExpr = *I; + ErrorRange = (*I)->getSourceRange(); ErrorSym = Sym; break; } @@ -2677,13 +2721,13 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, } // Evaluate the effect on the message receiver. - if (!ErrorExpr && Receiver) { - SymbolRef Sym = state->getSValAsScalarOrLoc(Receiver).getAsLocSymbol(); + if (!ErrorRange.isValid() && Receiver) { + SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol(); if (Sym) { if (const RefVal* T = state->get<RefBindings>(Sym)) { state = Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr); if (hasErr) { - ErrorExpr = Receiver; + ErrorRange = Receiver.getSourceRange(); ErrorSym = Sym; } } @@ -2692,7 +2736,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, // Process any errors. if (hasErr) { - ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, state, + ProcessNonLeakError(Dst, Builder, Ex, ErrorRange, Pred, state, hasErr, ErrorSym); return; } @@ -2703,7 +2747,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { bool found = false; if (Receiver) { - SVal V = state->getSValAsScalarOrLoc(Receiver); + SVal V = Receiver.getSValAsScalarOrLoc(state); if (SymbolRef Sym = V.getAsLocSymbol()) if (state->get<RefBindings>(Sym)) { found = true; @@ -2759,8 +2803,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, } case RetEffect::ReceiverAlias: { - assert (Receiver); - SVal V = state->getSValAsScalarOrLoc(Receiver); + assert(Receiver); + SVal V = Receiver.getSValAsScalarOrLoc(state); state = state->BindExpr(Ex, V, false); break; } @@ -2848,7 +2892,8 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, : Summaries.getClassMethodSummary(ME); assert(Summ && "RetainSummary is null"); - EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL, + EvalSummary(Dst, Eng, Builder, ME, + InstanceReceiver(ME, Pred->getLocationContext()), *Summ, NULL, ME->arg_begin(), ME->arg_end(), Pred, state); } @@ -3408,7 +3453,7 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, - Expr* NodeExpr, Expr* ErrorExpr, + Expr* NodeExpr, SourceRange ErrorRange, ExplodedNode* Pred, const GRState* St, RefVal::Kind hasErr, SymbolRef Sym) { @@ -3439,7 +3484,7 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, } CFRefReport *report = new CFRefReport(*BT, *this, N, Sym); - report->addRange(ErrorExpr->getSourceRange()); + report->addRange(ErrorRange); BR->EmitReport(report); } diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index 82e93a425e6e..9c6adc6bf2ee 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -14,6 +14,7 @@ add_clang_library(clangChecker BuiltinFunctionChecker.cpp CallAndMessageChecker.cpp CallInliner.cpp + CastSizeChecker.cpp CastToStructChecker.cpp CFRefCount.cpp CheckDeadStores.cpp @@ -69,3 +70,5 @@ add_clang_library(clangChecker ValueManager.cpp VLASizeChecker.cpp ) + +add_dependencies(clangChecker ClangStmtNodes) diff --git a/lib/Checker/CastSizeChecker.cpp b/lib/Checker/CastSizeChecker.cpp new file mode 100644 index 000000000000..754d775a65d1 --- /dev/null +++ b/lib/Checker/CastSizeChecker.cpp @@ -0,0 +1,82 @@ +//=== CastSizeChecker.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// CastSizeChecker checks when casting a malloc'ed symbolic region to type T, +// whether the size of the symbolic region is a multiple of the size of T. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/CharUnits.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "GRExprEngineInternalChecks.h" + +using namespace clang; + +namespace { +class CastSizeChecker : public CheckerVisitor<CastSizeChecker> { + BuiltinBug *BT; +public: + CastSizeChecker() : BT(0) {} + static void *getTag(); + void PreVisitCastExpr(CheckerContext &C, const CastExpr *B); +}; +} + +void *CastSizeChecker::getTag() { + static int x; + return &x; +} + +void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) { + const Expr *E = CE->getSubExpr(); + ASTContext &Ctx = C.getASTContext(); + QualType ToTy = Ctx.getCanonicalType(CE->getType()); + PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr()); + + if (!ToPTy) + return; + + QualType ToPointeeTy = ToPTy->getPointeeType(); + + const MemRegion *R = C.getState()->getSVal(E).getAsRegion(); + if (R == 0) + return; + + const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R); + if (SR == 0) + return; + + llvm::Optional<SVal> V = + C.getEngine().getStoreManager().getExtent(C.getState(), SR); + if (!V) + return; + + const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(V); + if (!CI) + return; + + CharUnits RegionSize = CharUnits::fromQuantity(CI->getValue().getSExtValue()); + CharUnits TypeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy); + if (RegionSize % TypeSize != 0) { + if (ExplodedNode *N = C.GenerateSink()) { + if (!BT) + BT = new BuiltinBug("Cast region with wrong size.", + "Cast a region whose size is not a multiple of the" + " destination type size."); + RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); + R->addRange(CE->getSourceRange()); + C.EmitReport(R); + } + } +} + + +void clang::RegisterCastSizeChecker(GRExprEngine &Eng) { + Eng.registerCheck(new CastSizeChecker()); +} diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp index c23be873f481..11ddaca9d6fc 100644 --- a/lib/Checker/CheckObjCDealloc.cpp +++ b/lib/Checker/CheckObjCDealloc.cpp @@ -115,7 +115,8 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, QualType T = ID->getType(); if (!T->isObjCObjectPointerType() || - ID->getAttr<IBOutletAttr>()) // Skip IBOutlets. + ID->getAttr<IBOutletAttr>() || // Skip IBOutlets. + ID->getAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections. continue; containsPointerIvar = true; diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp index 2af9ffa4a4d9..7f1c579c6edb 100644 --- a/lib/Checker/FlatStore.cpp +++ b/lib/Checker/FlatStore.cpp @@ -44,11 +44,11 @@ public: } SVal ArrayToPointer(Loc Array); - Store RemoveDeadBindings(Store store, Stmt* Loc, + const GRState *RemoveDeadBindings(GRState &state, Stmt* Loc, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){ - return store; + return StateMgr.getPersistentState(state); } Store BindDecl(Store store, const VarRegion *VR, SVal initVal); diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp index 00ac99559282..18e112cc8d36 100644 --- a/lib/Checker/GRCXXExprEngine.cpp +++ b/lib/Checker/GRCXXExprEngine.cpp @@ -86,7 +86,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, const CXXConstructorDecl *CD = E->getConstructor(); assert(CD); - if (!CD->isThisDeclarationADefinition()) + if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) // FIXME: invalidate the object. return; @@ -147,7 +147,7 @@ void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); assert(MD && "not a CXXMethodDecl?"); - if (!MD->isThisDeclarationADefinition()) + if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) // FIXME: conservative method call evaluation. return; diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 67090b86694f..24176586728c 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -1017,9 +1017,8 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred, GRBlockCounter BC) { - return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(), - B->getBlockID()) < 3; + B->getBlockID()) < AMgr.getMaxLoop(); } //===----------------------------------------------------------------------===// @@ -1810,6 +1809,28 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, } } +bool GRExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, + ExplodedNode *Pred) { + const GRState *state = GetState(Pred); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + + const FunctionDecl *FD = L.getAsFunctionDecl(); + if (!FD) + return false; + + if (!FD->getBody(FD)) + return false; + + // Now we have the definition of the callee, create a CallEnter node. + CallEnter Loc(CE, FD, Pred->getLocationContext()); + + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + if (N) + Dst.Add(N); + return true; +} + void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, @@ -1889,6 +1910,10 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, // If the callee is processed by a checker, skip the rest logic. if (CheckerEvalCall(CE, DstChecker, *DI)) DstTmp3.insert(DstChecker); + else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) { + // Callee is inlined. We shouldn't do post call checking. + return; + } else { for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), DE_Checker = DstChecker.end(); @@ -1944,7 +1969,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, //===----------------------------------------------------------------------===// static std::pair<const void*,const void*> EagerlyAssumeTag - = std::pair<const void*,const void*>(&EagerlyAssumeTag,0); + = std::pair<const void*,const void*>(&EagerlyAssumeTag,static_cast<void*>(0)); void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, Expr *Ex) { @@ -2595,8 +2620,8 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, Dst.Add(Pred); return; } - else if (T->isObjCInterfaceType()) { - // Some code tries to take the sizeof an ObjCInterfaceType, relying that + else if (T->getAs<ObjCObjectType>()) { + // Some code tries to take the sizeof an ObjCObjectType, relying that // the compiler has laid out its representation. Just report Unknown // for these. Dst.Add(Pred); diff --git a/lib/Checker/GRExprEngineExperimentalChecks.cpp b/lib/Checker/GRExprEngineExperimentalChecks.cpp index 89b4e4b6392f..6066a1c74d33 100644 --- a/lib/Checker/GRExprEngineExperimentalChecks.cpp +++ b/lib/Checker/GRExprEngineExperimentalChecks.cpp @@ -36,5 +36,6 @@ void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) { RegisterPointerSubChecker(Eng); RegisterPointerArithChecker(Eng); RegisterCastToStructChecker(Eng); + RegisterCastSizeChecker(Eng); RegisterArrayBoundChecker(Eng); } diff --git a/lib/Checker/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h index d1176001cac7..335b85e308e0 100644 --- a/lib/Checker/GRExprEngineInternalChecks.h +++ b/lib/Checker/GRExprEngineInternalChecks.h @@ -26,6 +26,7 @@ void RegisterAttrNonNullChecker(GRExprEngine &Eng); void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); void RegisterCallAndMessageChecker(GRExprEngine &Eng); void RegisterCastToStructChecker(GRExprEngine &Eng); +void RegisterCastSizeChecker(GRExprEngine &Eng); void RegisterDereferenceChecker(GRExprEngine &Eng); void RegisterDivZeroChecker(GRExprEngine &Eng); void RegisterFixedAddressChecker(GRExprEngine &Eng); diff --git a/lib/Checker/GRState.cpp b/lib/Checker/GRState.cpp index f68e10b0cbc9..b16e922776e5 100644 --- a/lib/Checker/GRState.cpp +++ b/lib/Checker/GRState.cpp @@ -51,11 +51,10 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, state, RegionRoots); // Clean up the store. - NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, LCtx, SymReaper, - RegionRoots); + const GRState *s = StoreMgr->RemoveDeadBindings(NewState, Loc, LCtx, + SymReaper, RegionRoots); - return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState), - SymReaper); + return ConstraintMgr->RemoveDeadBindings(s, SymReaper); } const GRState *GRState::unbindLoc(Loc LV) const { diff --git a/lib/Checker/LLVMConventionsChecker.cpp b/lib/Checker/LLVMConventionsChecker.cpp index 14f0fc1280df..39ded431279c 100644 --- a/lib/Checker/LLVMConventionsChecker.cpp +++ b/lib/Checker/LLVMConventionsChecker.cpp @@ -47,7 +47,7 @@ static bool InStdNamespace(const Decl *D) { } static bool IsStdString(QualType T) { - if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>()) + if (const ElaboratedType *QT = T->getAs<ElaboratedType>()) T = QT->getNamedType(); const TypedefType *TT = T->getAs<TypedefType>(); diff --git a/lib/Checker/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp index a22df3046920..086dbd8fdd36 100644 --- a/lib/Checker/MallocChecker.cpp +++ b/lib/Checker/MallocChecker.cpp @@ -182,7 +182,10 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, return state; SymbolRef Sym = ArgVal.getAsLocSymbol(); - assert(Sym); + + // Various cases could lead to non-symbol values here. + if (!Sym) + return state; const RefState *RS = state->get<RegionState>(Sym); diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp index 9a664c78a77c..575458c9dc79 100644 --- a/lib/Checker/MemRegion.cpp +++ b/lib/Checker/MemRegion.cpp @@ -539,7 +539,7 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx, const MemRegion* superRegion, ASTContext& Ctx){ - QualType T = Ctx.getCanonicalType(elementType); + QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType(); llvm::FoldingSetNodeID ID; ElementRegion::ProfileRegion(ID, T, Idx, superRegion); diff --git a/lib/Checker/ObjCUnusedIVarsChecker.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp index 0e47621d4205..2523cff9d8d0 100644 --- a/lib/Checker/ObjCUnusedIVarsChecker.cpp +++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp @@ -114,7 +114,8 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, // (b) explicitly marked unused // (c) are iboutlets if (ID->getAccessControl() != ObjCIvarDecl::Private || - ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>()) + ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() || + ID->getAttr<IBOutletCollectionAttr>()) continue; M[ID] = Unused; diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index 1e15d43a5ac2..c4072fd80307 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -352,9 +352,9 @@ public: // Part of public interface to class. /// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values. /// It returns a new Store with these values removed. - Store RemoveDeadBindings(Store store, Stmt* Loc, - const StackFrameContext *LCtx, - SymbolReaper& SymReaper, + const GRState *RemoveDeadBindings(GRState &state, Stmt* Loc, + const StackFrameContext *LCtx, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); const GRState *EnterStackFrame(const GRState *state, @@ -364,7 +364,18 @@ public: // Part of public interface to class. // Region "extents". //===------------------------------------------------------------------===// - const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent); + const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent){ + return state->set<RegionExtents>(R, Extent); + } + + Optional<SVal> getExtent(const GRState *state, const MemRegion *R) { + const SVal *V = state->get<RegionExtents>(R); + if (V) + return *V; + else + return Optional<SVal>(); + } + DefinedOrUnknownSVal getSizeInElements(const GRState *state, const MemRegion* R, QualType EleTy); @@ -798,12 +809,6 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, return UnknownVal(); } -const GRState *RegionStoreManager::setExtent(const GRState *state, - const MemRegion *region, - SVal extent) { - return state->set<RegionExtents>(region, extent); -} - //===----------------------------------------------------------------------===// // Location and region casting. //===----------------------------------------------------------------------===// @@ -1817,12 +1822,12 @@ bool RemoveDeadBindingsWorker::UpdatePostponed() { return changed; } -Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, +const GRState *RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) { - RegionBindings B = GetRegionBindings(store); + RegionBindings B = GetRegionBindings(state.getStore()); RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc, LCtx); W.GenerateClusters(); @@ -1855,8 +1860,16 @@ Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, for (; SI != SE; ++SI) SymReaper.maybeDead(*SI); } - - return B.getRoot(); + state.setStore(B.getRoot()); + const GRState *s = StateMgr.getPersistentState(state); + // Remove the extents of dead symbolic regions. + llvm::ImmutableMap<const MemRegion*,SVal> Extents = s->get<RegionExtents>(); + for (llvm::ImmutableMap<const MemRegion *, SVal>::iterator I=Extents.begin(), + E = Extents.end(); I != E; ++I) { + if (!W.isVisited(I->first)) + s = s->remove<RegionExtents>(I->first); + } + return s; } diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 8082b33fd66d..de58597e298d 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -24,6 +24,45 @@ using namespace clang; using namespace CodeGen; +/// CGBlockInfo - Information to generate a block literal. +class clang::CodeGen::CGBlockInfo { +public: + /// Name - The name of the block, kindof. + const char *Name; + + /// DeclRefs - Variables from parent scopes that have been + /// imported into this block. + llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs; + + /// InnerBlocks - This block and the blocks it encloses. + llvm::SmallPtrSet<const DeclContext *, 4> InnerBlocks; + + /// CXXThisRef - Non-null if 'this' was required somewhere, in + /// which case this is that expression. + const CXXThisExpr *CXXThisRef; + + /// NeedsObjCSelf - True if something in this block has an implicit + /// reference to 'self'. + bool NeedsObjCSelf; + + /// These are initialized by GenerateBlockFunction. + bool BlockHasCopyDispose; + CharUnits BlockSize; + CharUnits BlockAlign; + llvm::SmallVector<const Expr*, 8> BlockLayout; + + CGBlockInfo(const char *Name); +}; + +CGBlockInfo::CGBlockInfo(const char *N) + : Name(N), CXXThisRef(0), NeedsObjCSelf(false) { + + // Skip asm prefix, if any. + if (Name && Name[0] == '\01') + ++Name; +} + + llvm::Constant *CodeGenFunction:: BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size, const llvm::StructType* Ty, @@ -86,58 +125,86 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() { return NSConcreteStackBlock; } -static void CollectBlockDeclRefInfo( - const Stmt *S, CodeGenFunction::BlockInfo &Info, - llvm::SmallSet<const DeclContext *, 16> &InnerContexts) { +static void CollectBlockDeclRefInfo(const Stmt *S, CGBlockInfo &Info) { for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I) if (*I) - CollectBlockDeclRefInfo(*I, Info, InnerContexts); + CollectBlockDeclRefInfo(*I, Info); // We want to ensure we walk down into block literals so we can find // all nested BlockDeclRefExprs. if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) { - InnerContexts.insert(cast<DeclContext>(BE->getBlockDecl())); - CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); + Info.InnerBlocks.insert(BE->getBlockDecl()); + CollectBlockDeclRefInfo(BE->getBody(), Info); } - if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { + else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { + const ValueDecl *D = BDRE->getDecl(); // FIXME: Handle enums. - if (isa<FunctionDecl>(BDRE->getDecl())) + if (isa<FunctionDecl>(D)) return; + if (isa<ImplicitParamDecl>(D) && + isa<ObjCMethodDecl>(D->getDeclContext()) && + cast<ObjCMethodDecl>(D->getDeclContext())->getSelfDecl() == D) { + Info.NeedsObjCSelf = true; + return; + } + // Only Decls that escape are added. - if (!InnerContexts.count(BDRE->getDecl()->getDeclContext())) + if (!Info.InnerBlocks.count(D->getDeclContext())) Info.DeclRefs.push_back(BDRE); } + + // Make sure to capture implicit 'self' references due to super calls. + else if (const ObjCMessageExpr *E = dyn_cast<ObjCMessageExpr>(S)) { + if (E->getReceiverKind() == ObjCMessageExpr::SuperClass || + E->getReceiverKind() == ObjCMessageExpr::SuperInstance) + Info.NeedsObjCSelf = true; + } + + // Getter/setter uses may also cause implicit super references, + // which we can check for with: + else if (isa<ObjCSuperExpr>(S)) + Info.NeedsObjCSelf = true; + + else if (isa<CXXThisExpr>(S)) + Info.CXXThisRef = cast<CXXThisExpr>(S); } -/// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be +/// CanBlockBeGlobal - Given a CGBlockInfo struct, determines if a block can be /// declared as a global variable instead of on the stack. -static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) { +static bool CanBlockBeGlobal(const CGBlockInfo &Info) { return Info.DeclRefs.empty(); } /// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to /// ensure we can generate the debug information for the parameter for the block /// invoke function. -static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info, - CodeGenFunction *CGF) { - // FIXME: Also always forward the this pointer in C++ as well. +static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) { + if (Info.CXXThisRef) + CGF.AllocateBlockCXXThisPointer(Info.CXXThisRef); for (size_t i = 0; i < Info.DeclRefs.size(); ++i) - CGF->AllocateBlockDecl(Info.DeclRefs[i]); + CGF.AllocateBlockDecl(Info.DeclRefs[i]); + + if (Info.NeedsObjCSelf) { + ValueDecl *Self = cast<ObjCMethodDecl>(CGF.CurFuncDecl)->getSelfDecl(); + BlockDeclRefExpr *BDRE = + new (CGF.getContext()) BlockDeclRefExpr(Self, Self->getType(), + SourceLocation(), false); + Info.DeclRefs.push_back(BDRE); + CGF.AllocateBlockDecl(BDRE); + } } // FIXME: Push most into CGM, passing down a few bits, like current function // name. llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { - std::string Name = CurFn->getName(); - CodeGenFunction::BlockInfo Info(0, Name.c_str()); - llvm::SmallSet<const DeclContext *, 16> InnerContexts; - InnerContexts.insert(BE->getBlockDecl()); - CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); + CGBlockInfo Info(Name.c_str()); + Info.InnerBlocks.insert(BE->getBlockDecl()); + CollectBlockDeclRefInfo(BE->getBody(), Info); // Check if the block can be global. // FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like @@ -160,23 +227,15 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // We run this first so that we set BlockHasCopyDispose from the entire // block literal. // __invoke - CharUnits subBlockSize; - CharUnits subBlockAlign; - llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; - bool subBlockHasCopyDispose = false; llvm::Function *Fn = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl, - LocalDeclMap, - subBlockSize, - subBlockAlign, - subBlockDeclRefDecls, - subBlockHasCopyDispose); - BlockHasCopyDispose |= subBlockHasCopyDispose; + LocalDeclMap); + BlockHasCopyDispose |= Info.BlockHasCopyDispose; Elts[3] = Fn; // FIXME: Don't use BlockHasCopyDispose, it is set more often then // necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); } - if (subBlockHasCopyDispose) + if (Info.BlockHasCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; // __isa @@ -206,10 +265,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { C = llvm::ConstantInt::get(IntTy, 0); Elts[2] = C; - if (subBlockDeclRefDecls.size() == 0) { + if (Info.BlockLayout.empty()) { // __descriptor - Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize, - 0, 0); + Elts[4] = BuildDescriptorBlockDecl(BE, Info.BlockHasCopyDispose, + Info.BlockSize, 0, 0); // Optimize to being a global block. Elts[0] = CGM.getNSConcreteGlobalBlock(); @@ -227,13 +286,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { return C; } - std::vector<const llvm::Type *> Types(BlockFields+subBlockDeclRefDecls.size()); + std::vector<const llvm::Type *> Types(BlockFields+Info.BlockLayout.size()); for (int i=0; i<4; ++i) Types[i] = Elts[i]->getType(); Types[4] = PtrToInt8Ty; - for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { - const Expr *E = subBlockDeclRefDecls[i]; + for (unsigned i = 0, n = Info.BlockLayout.size(); i != n; ++i) { + const Expr *E = Info.BlockLayout[i]; const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); QualType Ty = E->getType(); if (BDRE && BDRE->isByRef()) { @@ -245,105 +304,113 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true); llvm::AllocaInst *A = CreateTempAlloca(Ty); - A->setAlignment(subBlockAlign.getQuantity()); + A->setAlignment(Info.BlockAlign.getQuantity()); V = A; - std::vector<HelperInfo> NoteForHelper(subBlockDeclRefDecls.size()); - int helpersize = 0; + // Build layout / cleanup information for all the data entries in the + // layout, and write the enclosing fields into the type. + std::vector<HelperInfo> NoteForHelper(Info.BlockLayout.size()); + unsigned NumHelpers = 0; for (unsigned i=0; i<4; ++i) Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); - for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) - { - // FIXME: Push const down. - Expr *E = const_cast<Expr*>(subBlockDeclRefDecls[i]); - DeclRefExpr *DR; - ValueDecl *VD; - - DR = dyn_cast<DeclRefExpr>(E); - // Skip padding. - if (DR) continue; - - BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); - VD = BDRE->getDecl(); - - llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp"); - NoteForHelper[helpersize].index = i+5; - NoteForHelper[helpersize].RequiresCopying - = BlockRequiresCopying(VD->getType()); - NoteForHelper[helpersize].flag - = (VD->getType()->isBlockPointerType() - ? BLOCK_FIELD_IS_BLOCK - : BLOCK_FIELD_IS_OBJECT); - - if (LocalDeclMap[VD]) { - if (BDRE->isByRef()) { - NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF | - // FIXME: Someone double check this. - (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0); - llvm::Value *Loc = LocalDeclMap[VD]; - Loc = Builder.CreateStructGEP(Loc, 1, "forwarding"); - Loc = Builder.CreateLoad(Loc); - Builder.CreateStore(Loc, Addr); - ++helpersize; - continue; - } else - E = new (getContext()) DeclRefExpr (VD, - VD->getType(), - SourceLocation()); - } + for (unsigned i=0; i < Info.BlockLayout.size(); ++i) { + const Expr *E = Info.BlockLayout[i]; + + // Skip padding. + if (isa<DeclRefExpr>(E)) continue; + + llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp"); + HelperInfo &Note = NoteForHelper[NumHelpers++]; + + Note.index = i+5; + + if (isa<CXXThisExpr>(E)) { + Note.RequiresCopying = false; + Note.flag = BLOCK_FIELD_IS_OBJECT; + + Builder.CreateStore(LoadCXXThis(), Addr); + continue; + } + + const BlockDeclRefExpr *BDRE = cast<BlockDeclRefExpr>(E); + const ValueDecl *VD = BDRE->getDecl(); + QualType T = VD->getType(); + + Note.RequiresCopying = BlockRequiresCopying(T); + + if (BDRE->isByRef()) { + Note.flag = BLOCK_FIELD_IS_BYREF; + if (T.isObjCGCWeak()) + Note.flag |= BLOCK_FIELD_IS_WEAK; + } else if (T->isBlockPointerType()) { + Note.flag = BLOCK_FIELD_IS_BLOCK; + } else { + Note.flag = BLOCK_FIELD_IS_OBJECT; + } + + if (LocalDeclMap[VD]) { if (BDRE->isByRef()) { - NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF | - // FIXME: Someone double check this. - (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0); - E = new (getContext()) - UnaryOperator(E, UnaryOperator::AddrOf, - getContext().getPointerType(E->getType()), - SourceLocation()); - } - ++helpersize; - - RValue r = EmitAnyExpr(E, Addr, false); - if (r.isScalar()) { - llvm::Value *Loc = r.getScalarVal(); - const llvm::Type *Ty = Types[i+BlockFields]; - if (BDRE->isByRef()) { - // E is now the address of the value field, instead, we want the - // address of the actual ByRef struct. We optimize this slightly - // compared to gcc by not grabbing the forwarding slot as this must - // be done during Block_copy for us, and we can postpone the work - // until then. - CharUnits offset = BlockDecls[BDRE->getDecl()]; - - llvm::Value *BlockLiteral = LoadBlockStruct(); - - Loc = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset.getQuantity()), - "block.literal"); - Ty = llvm::PointerType::get(Ty, 0); - Loc = Builder.CreateBitCast(Loc, Ty); - Loc = Builder.CreateLoad(Loc); - // Loc = Builder.CreateBitCast(Loc, Ty); - } + llvm::Value *Loc = LocalDeclMap[VD]; + Loc = Builder.CreateStructGEP(Loc, 1, "forwarding"); + Loc = Builder.CreateLoad(Loc); Builder.CreateStore(Loc, Addr); - } else if (r.isComplex()) - // FIXME: implement - ErrorUnsupported(BE, "complex in block literal"); - else if (r.isAggregate()) - ; // Already created into the destination - else - assert (0 && "bad block variable"); - // FIXME: Ensure that the offset created by the backend for - // the struct matches the previously computed offset in BlockDecls. + continue; + } else { + E = new (getContext()) DeclRefExpr(const_cast<ValueDecl*>(VD), + VD->getType(), + SourceLocation()); + } } - NoteForHelper.resize(helpersize); + + if (BDRE->isByRef()) { + E = new (getContext()) + UnaryOperator(const_cast<Expr*>(E), UnaryOperator::AddrOf, + getContext().getPointerType(E->getType()), + SourceLocation()); + } + + RValue r = EmitAnyExpr(E, Addr, false); + if (r.isScalar()) { + llvm::Value *Loc = r.getScalarVal(); + const llvm::Type *Ty = Types[i+BlockFields]; + if (BDRE->isByRef()) { + // E is now the address of the value field, instead, we want the + // address of the actual ByRef struct. We optimize this slightly + // compared to gcc by not grabbing the forwarding slot as this must + // be done during Block_copy for us, and we can postpone the work + // until then. + CharUnits offset = BlockDecls[BDRE->getDecl()]; + + llvm::Value *BlockLiteral = LoadBlockStruct(); + + Loc = Builder.CreateGEP(BlockLiteral, + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + offset.getQuantity()), + "block.literal"); + Ty = llvm::PointerType::get(Ty, 0); + Loc = Builder.CreateBitCast(Loc, Ty); + Loc = Builder.CreateLoad(Loc); + // Loc = Builder.CreateBitCast(Loc, Ty); + } + Builder.CreateStore(Loc, Addr); + } else if (r.isComplex()) + // FIXME: implement + ErrorUnsupported(BE, "complex in block literal"); + else if (r.isAggregate()) + ; // Already created into the destination + else + assert (0 && "bad block variable"); + // FIXME: Ensure that the offset created by the backend for + // the struct matches the previously computed offset in BlockDecls. + } + NoteForHelper.resize(NumHelpers); // __descriptor llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE, - subBlockHasCopyDispose, - subBlockSize, Ty, + Info.BlockHasCopyDispose, + Info.BlockSize, Ty, &NoteForHelper); Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty); Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp")); @@ -487,13 +554,25 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, return EmitCall(FnInfo, Func, ReturnValue, Args); } -CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { +void CodeGenFunction::AllocateBlockCXXThisPointer(const CXXThisExpr *E) { + assert(BlockCXXThisOffset.isZero() && "already computed 'this' pointer"); + + // Figure out what the offset is. + QualType T = E->getType(); + std::pair<CharUnits,CharUnits> TypeInfo = getContext().getTypeInfoInChars(T); + CharUnits Offset = getBlockOffset(TypeInfo.first, TypeInfo.second); + + BlockCXXThisOffset = Offset; + BlockLayout.push_back(E); +} + +void CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { const ValueDecl *VD = E->getDecl(); - CharUnits &offset = BlockDecls[VD]; + CharUnits &Offset = BlockDecls[VD]; // See if we have already allocated an offset for this variable. - if (offset.isPositive()) - return offset; + if (!Offset.isZero()) + return; // Don't run the expensive check, unless we have to. if (!BlockHasCopyDispose) @@ -501,23 +580,34 @@ CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { || BlockRequiresCopying(E->getType())) BlockHasCopyDispose = true; - // if not, allocate one now. - offset = getBlockOffset(E); + const ValueDecl *D = cast<ValueDecl>(E->getDecl()); - return offset; + CharUnits Size; + CharUnits Align; + + if (E->isByRef()) { + llvm::tie(Size,Align) = + getContext().getTypeInfoInChars(getContext().VoidPtrTy); + } else { + Size = getContext().getTypeSizeInChars(D->getType()); + Align = getContext().getDeclAlign(D); + } + + Offset = getBlockOffset(Size, Align); + BlockLayout.push_back(E); } -llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { - const ValueDecl *VD = E->getDecl(); - CharUnits offset = AllocateBlockDecl(E); - +llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const ValueDecl *VD, + bool IsByRef) { + CharUnits offset = BlockDecls[VD]; + assert(!offset.isZero() && "getting address of unallocated decl"); llvm::Value *BlockLiteral = LoadBlockStruct(); llvm::Value *V = Builder.CreateGEP(BlockLiteral, llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), offset.getQuantity()), "block.literal"); - if (E->isByRef()) { + if (IsByRef) { const llvm::Type *PtrStructTy = llvm::PointerType::get(BuildByRefType(VD), 0); // The block literal will need a copy/destroy helper. @@ -543,19 +633,6 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { return V; } -void CodeGenFunction::BlockForwardSelf() { - const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); - ImplicitParamDecl *SelfDecl = OMD->getSelfDecl(); - llvm::Value *&DMEntry = LocalDeclMap[SelfDecl]; - if (DMEntry) - return; - // FIXME - Eliminate BlockDeclRefExprs, clients don't need/want to care - BlockDeclRefExpr *BDRE = new (getContext()) - BlockDeclRefExpr(SelfDecl, - SelfDecl->getType(), SourceLocation(), false); - DMEntry = GetAddrOfBlockDecl(BDRE); -} - llvm::Constant * BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // Generate the block descriptor. @@ -600,19 +677,11 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { std::vector<llvm::Constant*> LiteralFields(FieldCount); - CodeGenFunction::BlockInfo Info(0, n); - CharUnits subBlockSize; - CharUnits subBlockAlign; - llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; - bool subBlockHasCopyDispose = false; + CGBlockInfo Info(n); llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; llvm::Function *Fn - = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap, - subBlockSize, - subBlockAlign, - subBlockDeclRefDecls, - subBlockHasCopyDispose); - assert(subBlockSize == BlockLiteralSize + = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap); + assert(Info.BlockSize == BlockLiteralSize && "no imports allowed for global block"); // isa @@ -651,13 +720,9 @@ llvm::Value *CodeGenFunction::LoadBlockStruct() { llvm::Function * CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, - const BlockInfo& Info, + CGBlockInfo &Info, const Decl *OuterFuncDecl, - llvm::DenseMap<const Decl*, llvm::Value*> ldm, - CharUnits &Size, - CharUnits &Align, - llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls, - bool &subBlockHasCopyDispose) { + llvm::DenseMap<const Decl*, llvm::Value*> ldm) { // Check if we should generate debug info for this block. if (CGM.getDebugInfo()) @@ -701,11 +766,12 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); - // Allocate all BlockDeclRefDecls, so we can calculate the right ParmTy below. - AllocateAllBlockDeclRefs(Info, this); + // Build the block struct now. + AllocateAllBlockDeclRefs(*this, Info); QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose, - BlockDeclRefDecls); + BlockLayout); + // FIXME: This leaks ImplicitParamDecl *SelfDecl = ImplicitParamDecl::Create(getContext(), const_cast<BlockDecl*>(BD), @@ -725,10 +791,11 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic); + MangleBuffer Name; + CGM.getMangledName(Name, BD); llvm::Function *Fn = - llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - llvm::Twine("__") + Info.Name + "_block_invoke_", - &CGM.getModule()); + llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, + Name.getString(), &CGM.getModule()); CGM.SetInternalFunctionAttributes(BD, Fn, FI); @@ -738,6 +805,34 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, CurFuncDecl = OuterFuncDecl; CurCodeDecl = BD; + // If we have a C++ 'this' reference, go ahead and force it into + // existence now. + if (Info.CXXThisRef) { + assert(!BlockCXXThisOffset.isZero() && + "haven't yet allocated 'this' reference"); + + // TODO: I have a dream that one day this will be typed. + llvm::Value *BlockLiteral = LoadBlockStruct(); + llvm::Value *ThisPtrRaw = + Builder.CreateConstInBoundsGEP1_64(BlockLiteral, + BlockCXXThisOffset.getQuantity(), + "this.ptr.raw"); + + const llvm::Type *Ty = + CGM.getTypes().ConvertType(Info.CXXThisRef->getType()); + Ty = llvm::PointerType::get(Ty, 0); + llvm::Value *ThisPtr = Builder.CreateBitCast(ThisPtrRaw, Ty, "this.ptr"); + + CXXThisValue = Builder.CreateLoad(ThisPtr, "this"); + } + + // If we have an Objective C 'self' reference, go ahead and force it + // into existence now. + if (Info.NeedsObjCSelf) { + ValueDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl(); + LocalDeclMap[Self] = GetAddrOfBlockDecl(Self, false); + } + // Save a spot to insert the debug information for all the BlockDeclRefDecls. llvm::BasicBlock *entry = Builder.GetInsertBlock(); llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); @@ -754,9 +849,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, if (CGDebugInfo *DI = getDebugInfo()) { // Emit debug information for all the BlockDeclRefDecls. - for (unsigned i = 0, e = BlockDeclRefDecls.size(); i != e; ++i) { - if (const BlockDeclRefExpr *BDRE = - dyn_cast<BlockDeclRefExpr>(BlockDeclRefDecls[i])) { + // FIXME: also for 'this' + for (unsigned i = 0, e = BlockLayout.size(); i != e; ++i) { + if (const BlockDeclRefExpr *BDRE = + dyn_cast<BlockDeclRefExpr>(BlockLayout[i])) { const ValueDecl *D = BDRE->getDecl(); DI->setLocation(D->getLocation()); DI->EmitDeclareOfBlockDeclRefVariable(BDRE, @@ -779,25 +875,15 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign.getQuantity())); - Size = BlockOffset; - Align = BlockAlign; - subBlockDeclRefDecls = BlockDeclRefDecls; - subBlockHasCopyDispose |= BlockHasCopyDispose; + Info.BlockSize = BlockOffset; + Info.BlockAlign = BlockAlign; + Info.BlockLayout = BlockLayout; + Info.BlockHasCopyDispose = BlockHasCopyDispose; return Fn; } -CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { - const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl()); - - CharUnits Size = getContext().getTypeSizeInChars(D->getType()); - CharUnits Align = getContext().getDeclAlign(D); - - if (BDRE->isByRef()) { - Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy); - Align = getContext().getTypeAlignInChars(getContext().VoidPtrTy); - } - - assert ((Align.isPositive()) && "alignment must be 1 byte or more"); +CharUnits BlockFunction::getBlockOffset(CharUnits Size, CharUnits Align) { + assert((Align.isPositive()) && "alignment must be 1 byte or more"); CharUnits OldOffset = BlockOffset; @@ -808,23 +894,22 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { CharUnits Pad = BlockOffset - OldOffset; if (Pad.isPositive()) { - llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad.getQuantity()); QualType PadTy = getContext().getConstantArrayType(getContext().CharTy, llvm::APInt(32, Pad.getQuantity()), ArrayType::Normal, 0); - ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(), + ValueDecl *PadDecl = VarDecl::Create(getContext(), + getContext().getTranslationUnitDecl(), + SourceLocation(), 0, QualType(PadTy), 0, VarDecl::None, VarDecl::None); - Expr *E; - E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), - SourceLocation()); - BlockDeclRefDecls.push_back(E); + Expr *E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), + SourceLocation()); + BlockLayout.push_back(E); } - BlockDeclRefDecls.push_back(BDRE); BlockOffset += Size; - return BlockOffset-Size; + return BlockOffset - Size; } llvm::Constant *BlockFunction:: diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 5646d0036e90..e9b2bd549af5 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -148,26 +148,6 @@ public: BLOCK_BYREF_CURRENT_MAX = 256 }; - /// BlockInfo - Information to generate a block literal. - struct BlockInfo { - /// BlockLiteralTy - The type of the block literal. - const llvm::Type *BlockLiteralTy; - - /// Name - the name of the function this block was created for, if any. - const char *Name; - - /// ByCopyDeclRefs - Variables from parent scopes that have been imported - /// into this block. - llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs; - - BlockInfo(const llvm::Type *blt, const char *n) - : BlockLiteralTy(blt), Name(n) { - // Skip asm prefix, if any. - if (Name && Name[0] == '\01') - ++Name; - } - }; - CGBuilderTy &Builder; BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf, CGBuilderTy &B); @@ -179,19 +159,31 @@ public: /// characters. CharUnits BlockAlign; - /// getBlockOffset - Allocate an offset for the ValueDecl from a - /// BlockDeclRefExpr in a block literal (BlockExpr). - CharUnits getBlockOffset(const BlockDeclRefExpr *E); + /// getBlockOffset - Allocate a location within the block's storage + /// for a value with the given size and alignment requirements. + CharUnits getBlockOffset(CharUnits Size, CharUnits Align); /// BlockHasCopyDispose - True iff the block uses copy/dispose. bool BlockHasCopyDispose; - /// BlockDeclRefDecls - Decls from BlockDeclRefExprs in apperance order - /// in a block literal. Decls without names are used for padding. - llvm::SmallVector<const Expr *, 8> BlockDeclRefDecls; + /// BlockLayout - The layout of the block's storage, represented as + /// a sequence of expressions which require such storage. The + /// expressions can be: + /// - a BlockDeclRefExpr, indicating that the given declaration + /// from an enclosing scope is needed by the block; + /// - a DeclRefExpr, which always wraps an anonymous VarDecl with + /// array type, used to insert padding into the block; or + /// - a CXXThisExpr, indicating that the C++ 'this' value should + /// propagate from the parent to the block. + /// This is a really silly representation. + llvm::SmallVector<const Expr *, 8> BlockLayout; /// BlockDecls - Offsets for all Decls in BlockDeclRefExprs. - std::map<const Decl*, CharUnits> BlockDecls; + llvm::DenseMap<const Decl*, CharUnits> BlockDecls; + + /// BlockCXXThisOffset - The offset of the C++ 'this' value within + /// the block structure. + CharUnits BlockCXXThisOffset; ImplicitParamDecl *BlockStructDecl; ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; } diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 95c41db86e09..dd505c2ae88f 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -71,7 +71,7 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF, /// Utility to insert an atomic instruction based Instrinsic::ID and // the expression node, where the return value is the result of the // operation. -static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF, +static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF, Intrinsic::ID Id, const CallExpr *E, Instruction::BinaryOps Op) { const llvm::Type *ResType[2]; @@ -88,6 +88,30 @@ static llvm::ConstantInt *getInt32(llvm::LLVMContext &Context, int32_t Value) { return llvm::ConstantInt::get(llvm::Type::getInt32Ty(Context), Value); } + +/// EmitFAbs - Emit a call to fabs/fabsf/fabsl, depending on the type of ValTy, +/// which must be a scalar floating point type. +static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) { + const BuiltinType *ValTyP = ValTy->getAs<BuiltinType>(); + assert(ValTyP && "isn't scalar fp type!"); + + StringRef FnName; + switch (ValTyP->getKind()) { + default: assert(0 && "Isn't a scalar fp type!"); + case BuiltinType::Float: FnName = "fabsf"; break; + case BuiltinType::Double: FnName = "fabs"; break; + case BuiltinType::LongDouble: FnName = "fabsl"; break; + } + + // The prototype is something that takes and returns whatever V's type is. + std::vector<const llvm::Type*> Args; + Args.push_back(V->getType()); + llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), Args, false); + llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName); + + return CGF.Builder.CreateCall(Fn, V, "abs"); +} + RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E) { // See if we can constant fold this builtin. If so, don't emit it at all. @@ -328,6 +352,50 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, V = Builder.CreateFCmpUNO(V, V, "cmp"); return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp")); } + + case Builtin::BI__builtin_isinf: { + // isinf(x) --> fabs(x) == infinity + Value *V = EmitScalarExpr(E->getArg(0)); + V = EmitFAbs(*this, V, E->getArg(0)->getType()); + + V = Builder.CreateFCmpOEQ(V, ConstantFP::getInfinity(V->getType()),"isinf"); + return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp")); + } + + // TODO: BI__builtin_isinf_sign + // isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 + + case Builtin::BI__builtin_isnormal: { + // isnormal(x) --> x == x && fabsf(x) < infinity && fabsf(x) >= float_min + Value *V = EmitScalarExpr(E->getArg(0)); + Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq"); + + Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType()); + Value *IsLessThanInf = + Builder.CreateFCmpULT(Abs, ConstantFP::getInfinity(V->getType()),"isinf"); + APFloat Smallest = APFloat::getSmallestNormalized( + getContext().getFloatTypeSemantics(E->getArg(0)->getType())); + Value *IsNormal = + Builder.CreateFCmpUGE(Abs, ConstantFP::get(V->getContext(), Smallest), + "isnormal"); + V = Builder.CreateAnd(Eq, IsLessThanInf, "and"); + V = Builder.CreateAnd(V, IsNormal, "and"); + return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); + } + + case Builtin::BI__builtin_isfinite: { + // isfinite(x) --> x == x && fabs(x) != infinity; } + Value *V = EmitScalarExpr(E->getArg(0)); + Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq"); + + Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType()); + Value *IsNotInf = + Builder.CreateFCmpUNE(Abs, ConstantFP::getInfinity(V->getType()),"isinf"); + + V = Builder.CreateAnd(Eq, IsNotInf, "and"); + return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); + } + case Builtin::BIalloca: case Builtin::BI__builtin_alloca: { // FIXME: LLVM IR Should allow alloca with an i64 size! diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 74cf1134d5b7..525877903e7a 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -13,6 +13,7 @@ // We might split this into multiple files if it gets too unwieldy +#include "CGCXXABI.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "Mangle.h" @@ -206,6 +207,7 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, return; llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXConstructor(D, Type)); + setFunctionLinkage(D, Fn); CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); @@ -229,6 +231,10 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } +void CodeGenModule::getMangledName(MangleBuffer &Buffer, const BlockDecl *BD) { + getMangleContext().mangleBlock(BD, Buffer.getBuffer()); +} + void CodeGenModule::getMangledCXXCtorName(MangleBuffer &Name, const CXXConstructorDecl *D, CXXCtorType Type) { @@ -269,6 +275,7 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, return; llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXDestructor(D, Type)); + setFunctionLinkage(D, Fn); CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); @@ -327,3 +334,5 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } + +CXXABI::~CXXABI() {} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h new file mode 100644 index 000000000000..a7e18714e8b3 --- /dev/null +++ b/lib/CodeGen/CGCXXABI.h @@ -0,0 +1,37 @@ +//===----- CGCXXABI.h - Interface to C++ ABIs -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for C++ code generation. Concrete subclasses +// of this implement code generation for specific C++ ABIs. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CXXABI_H +#define CLANG_CODEGEN_CXXABI_H + +namespace clang { +namespace CodeGen { + class CodeGenModule; + class MangleContext; + +/// Implements C++ ABI-specific code generation functions. +class CXXABI { +public: + virtual ~CXXABI(); + + /// Gets the mangle context. + virtual MangleContext &getMangleContext() = 0; +}; + +/// Creates an instance of a C++ ABI class. +CXXABI *CreateItaniumCXXABI(CodeGenModule &CGM); +} +} + +#endif diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 92d15d9d8c97..73cee3c10d2e 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -38,6 +38,7 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) { default: return llvm::CallingConv::C; case CC_X86StdCall: return llvm::CallingConv::X86_StdCall; case CC_X86FastCall: return llvm::CallingConv::X86_FastCall; + case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall; } } @@ -97,6 +98,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) { if (D->hasAttr<FastCallAttr>()) return CC_X86FastCall; + if (D->hasAttr<ThisCallAttr>()) + return CC_X86ThisCall; + return CC_C; } @@ -858,6 +862,36 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, } } +RValue CodeGenFunction::EmitDelegateCallArg(const VarDecl *Param) { + // StartFunction converted the ABI-lowered parameter(s) into a + // local alloca. We need to turn that into an r-value suitable + // for EmitCall. + llvm::Value *Local = GetAddrOfLocalVar(Param); + + QualType ArgType = Param->getType(); + + // For the most part, we just need to load the alloca, except: + // 1) aggregate r-values are actually pointers to temporaries, and + // 2) references to aggregates are pointers directly to the aggregate. + // I don't know why references to non-aggregates are different here. + if (const ReferenceType *RefType = ArgType->getAs<ReferenceType>()) { + if (hasAggregateLLVMType(RefType->getPointeeType())) + return RValue::getAggregate(Local); + + // Locals which are references to scalars are represented + // with allocas holding the pointer. + return RValue::get(Builder.CreateLoad(Local)); + } + + if (ArgType->isAnyComplexType()) + return RValue::getComplex(LoadComplexFromAddr(Local, /*volatile*/ false)); + + if (hasAggregateLLVMType(ArgType)) + return RValue::getAggregate(Local); + + return RValue::get(EmitLoadOfScalar(Local, false, ArgType)); +} + RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) { if (ArgType->isReferenceType()) return EmitReferenceBindingToExpr(E); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index a604eef49a13..bebea549f965 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -262,102 +262,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, return Value; } - -/// EmitCopyCtorCall - Emit a call to a copy constructor. -static void -EmitCopyCtorCall(CodeGenFunction &CGF, const CXXConstructorDecl *CopyCtor, - llvm::Value *ThisPtr, llvm::Value *Src) { - llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, Ctor_Complete); - - CallArgList CallArgs; - - // Push the this ptr. - CallArgs.push_back(std::make_pair(RValue::get(ThisPtr), - CopyCtor->getThisType(CGF.getContext()))); - - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - CopyCtor->getParamDecl(0)->getType())); - - - { - CodeGenFunction::CXXTemporariesCleanupScope Scope(CGF); - - // If the copy constructor has default arguments, emit them. - for (unsigned I = 1, E = CopyCtor->getNumParams(); I < E; ++I) { - const ParmVarDecl *Param = CopyCtor->getParamDecl(I); - const Expr *DefaultArgExpr = Param->getDefaultArg(); - - assert(DefaultArgExpr && "Ctor parameter must have default arg!"); - - QualType ArgType = Param->getType(); - CallArgs.push_back(std::make_pair(CGF.EmitCallArg(DefaultArgExpr, - ArgType), - ArgType)); - } - - const FunctionProtoType *FPT = - CopyCtor->getType()->getAs<FunctionProtoType>(); - CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, CopyCtor); - } -} -/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class -/// array of objects from SrcValue to DestValue. Copying can be either a bitwise -/// copy or via a copy constructor call. -// FIXME. Consolidate this with EmitCXXAggrConstructorCall. -void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, - llvm::Value *Src, - const ConstantArrayType *Array, - const CXXRecordDecl *ClassDecl) { - // Create a temporary for the loop index and initialize it with 0. - llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), - "loop.index"); - llvm::Value* zeroConstant = - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); - Builder.CreateStore(zeroConstant, IndexPtr); - // Start the loop with a block that tests the condition. - llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); - llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); - - EmitBlock(CondBlock); - - llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - // Generate: if (loop-index < number-of-elements fall to the loop body, - // otherwise, go to the block after the for-loop. - uint64_t NumElements = getContext().getConstantArrayElementCount(Array); - llvm::Value * NumElementsPtr = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); - llvm::Value *Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, - "isless"); - // If the condition is true, execute the body. - Builder.CreateCondBr(IsLess, ForBody, AfterFor); - - EmitBlock(ForBody); - llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); - // Inside the loop body, emit the constructor call on the array element. - Counter = Builder.CreateLoad(IndexPtr); - Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); - Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); - EmitClassMemberwiseCopy(Dest, Src, ClassDecl); - - EmitBlock(ContinueBlock); - - // Emit the increment of the loop counter. - llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); - Counter = Builder.CreateLoad(IndexPtr); - NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr); - - // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor, true); -} - /// GetVTTParameter - Return the VTT parameter that should be passed to a /// base constructor/destructor with virtual bases. static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, @@ -405,111 +310,6 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, return VTT; } - -/// EmitClassMemberwiseCopy - This routine generates code to copy a class -/// object from SrcValue to DestValue. Copying can be either a bitwise copy -/// or via a copy constructor call. -void CodeGenFunction::EmitClassMemberwiseCopy( - llvm::Value *Dest, llvm::Value *Src, - const CXXRecordDecl *ClassDecl) { - if (ClassDecl->hasTrivialCopyConstructor()) { - EmitAggregateCopy(Dest, Src, getContext().getTagDeclType(ClassDecl)); - return; - } - - CXXConstructorDecl *CopyCtor = ClassDecl->getCopyConstructor(getContext(), 0); - assert(CopyCtor && "Did not have copy ctor!"); - - EmitCopyCtorCall(*this, CopyCtor, Dest, Src); -} - -/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a -/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03 -/// The implicitly-defined copy constructor for class X performs a memberwise -/// copy of its subobjects. The order of copying is the same as the order of -/// initialization of bases and members in a user-defined constructor -/// Each subobject is copied in the manner appropriate to its type: -/// if the subobject is of class type, the copy constructor for the class is -/// used; -/// if the subobject is an array, each element is copied, in the manner -/// appropriate to the element type; -/// if the subobject is of scalar type, the built-in assignment operator is -/// used. -/// Virtual base class subobjects shall be copied only once by the -/// implicitly-defined copy constructor - -void -CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { - const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl()); - CXXCtorType CtorType = CurGD.getCtorType(); - (void) CtorType; - - const CXXRecordDecl *ClassDecl = Ctor->getParent(); - assert(!ClassDecl->hasUserDeclaredCopyConstructor() && - "SynthesizeCXXCopyConstructor - copy constructor has definition already"); - assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); - - llvm::Value *ThisPtr = LoadCXXThis(); - - // Find the source pointer. - unsigned SrcArgIndex = Args.size() - 1; - assert(CtorType == Ctor_Base || SrcArgIndex == 1); - assert(CtorType != Ctor_Base || - (ClassDecl->getNumVBases() != 0 && SrcArgIndex == 2) || - SrcArgIndex == 1); - - llvm::Value *SrcPtr = - Builder.CreateLoad(GetAddrOfLocalVar(Args[SrcArgIndex].first)); - - for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), - E = ClassDecl->field_end(); I != E; ++I) { - const FieldDecl *Field = *I; - - QualType FieldType = getContext().getCanonicalType(Field->getType()); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(ThisPtr, Field, 0); - LValue RHS = EmitLValueForField(SrcPtr, Field, 0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType)->getPointerTo(); - llvm::Value *DestBaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - llvm::Value *SrcBaseAddrPtr = - Builder.CreateBitCast(RHS.getAddress(), BasePtr); - EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array, - FieldClassDecl); - } - else - EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), - FieldClassDecl); - continue; - } - - // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForFieldInitialization(ThisPtr, Field, 0); - LValue RHS = EmitLValueForFieldInitialization(SrcPtr, Field, 0); - - if (!hasAggregateLLVMType(Field->getType())) { - RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); - EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); - } else if (Field->getType()->isAnyComplexType()) { - ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), - RHS.isVolatileQualified()); - StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); - } else { - EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); - } - } - - InitializeVTablePointers(ClassDecl); -} - static void EmitBaseInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXBaseOrMemberInitializer *BaseInit, @@ -547,9 +347,97 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, } } +static void EmitAggMemberInitializer(CodeGenFunction &CGF, + LValue LHS, + llvm::Value *ArrayIndexVar, + CXXBaseOrMemberInitializer *MemberInit, + QualType T, + unsigned Index) { + if (Index == MemberInit->getNumArrayIndices()) { + CodeGenFunction::CleanupScope Cleanups(CGF); + + llvm::Value *Dest = LHS.getAddress(); + if (ArrayIndexVar) { + // If we have an array index variable, load it and use it as an offset. + // Then, increment the value. + llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar); + Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress"); + llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1); + Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc"); + CGF.Builder.CreateStore(Next, ArrayIndexVar); + } + + CGF.EmitAggExpr(MemberInit->getInit(), Dest, + LHS.isVolatileQualified(), + /*IgnoreResult*/ false, + /*IsInitializer*/ true); + + return; + } + + const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(T); + assert(Array && "Array initialization without the array type?"); + llvm::Value *IndexVar + = CGF.GetAddrOfLocalVar(MemberInit->getArrayIndex(Index)); + assert(IndexVar && "Array index variable not loaded"); + + // Initialize this index variable to zero. + llvm::Value* Zero + = llvm::Constant::getNullValue( + CGF.ConvertType(CGF.getContext().getSizeType())); + CGF.Builder.CreateStore(Zero, IndexVar); + + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = CGF.createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = CGF.createBasicBlock("for.end"); + + CGF.EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = CGF.createBasicBlock("for.body"); + // Generate: if (loop-index < number-of-elements) fall to the loop body, + // otherwise, go to the block after the for-loop. + uint64_t NumElements = Array->getSize().getZExtValue(); + llvm::Value *Counter = CGF.Builder.CreateLoad(IndexVar); + llvm::Value *NumElementsPtr = + llvm::ConstantInt::get(Counter->getType(), NumElements); + llvm::Value *IsLess = CGF.Builder.CreateICmpULT(Counter, NumElementsPtr, + "isless"); + + // If the condition is true, execute the body. + CGF.Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + CGF.EmitBlock(ForBody); + llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc"); + + { + CodeGenFunction::CleanupScope Cleanups(CGF); + + // Inside the loop body recurse to emit the inner loop or, eventually, the + // constructor call. + EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit, + Array->getElementType(), Index + 1); + } + + CGF.EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); + Counter = CGF.Builder.CreateLoad(IndexVar); + NextVal = CGF.Builder.CreateAdd(Counter, NextVal, "inc"); + CGF.Builder.CreateStore(NextVal, IndexVar); + + // Finally, branch back up to the condition for the next iteration. + CGF.EmitBranch(CondBlock); + + // Emit the fall-through block. + CGF.EmitBlock(AfterFor, true); +} + static void EmitMemberInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, - CXXBaseOrMemberInitializer *MemberInit) { + CXXBaseOrMemberInitializer *MemberInit, + const CXXConstructorDecl *Constructor, + FunctionArgList &Args) { assert(MemberInit->isMemberInitializer() && "Must have member initializer!"); @@ -558,13 +446,15 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, QualType FieldType = CGF.getContext().getCanonicalType(Field->getType()); llvm::Value *ThisPtr = CGF.LoadCXXThis(); - LValue LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0); + LValue LHS; // If we are initializing an anonymous union field, drill down to the field. if (MemberInit->getAnonUnionMember()) { Field = MemberInit->getAnonUnionMember(); - LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, 0); + LHS = CGF.EmitLValueForAnonRecordField(ThisPtr, Field, 0); FieldType = Field->getType(); + } else { + LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0); } // FIXME: If there's no initializer and the CXXBaseOrMemberInitializer @@ -575,7 +465,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, /*IsInitializer=*/true); CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); } else if (FieldType->isArrayType() && !MemberInit->getInit()) { - CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType()); + CGF.EmitNullInitialization(LHS.getAddress(), Field->getType()); } else if (!CGF.hasAggregateLLVMType(Field->getType())) { RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit(), true)); CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); @@ -583,14 +473,61 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(), LHS.isVolatileQualified()); } else { - CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(), - LHS.isVolatileQualified(), - /*IgnoreResult*/ false, - /*IsInitializer*/ true); + llvm::Value *ArrayIndexVar = 0; + const ConstantArrayType *Array + = CGF.getContext().getAsConstantArrayType(FieldType); + if (Array && Constructor->isImplicit() && + Constructor->isCopyConstructor()) { + const llvm::Type *SizeTy + = CGF.ConvertType(CGF.getContext().getSizeType()); + + // The LHS is a pointer to the first object we'll be constructing, as + // a flat array. + QualType BaseElementTy = CGF.getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(LHS.getAddress(), + BasePtr); + LHS = LValue::MakeAddr(BaseAddrPtr, CGF.MakeQualifiers(BaseElementTy)); + + // Create an array index that will be used to walk over all of the + // objects we're constructing. + ArrayIndexVar = CGF.CreateTempAlloca(SizeTy, "object.index"); + llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy); + CGF.Builder.CreateStore(Zero, ArrayIndexVar); + + // If we are copying an array of scalars or classes with trivial copy + // constructors, perform a single aggregate copy. + const RecordType *Record = BaseElementTy->getAs<RecordType>(); + if (!Record || + cast<CXXRecordDecl>(Record->getDecl())->hasTrivialCopyConstructor()) { + // Find the source pointer. We knows it's the last argument because + // we know we're in a copy constructor. + unsigned SrcArgIndex = Args.size() - 1; + llvm::Value *SrcPtr + = CGF.Builder.CreateLoad( + CGF.GetAddrOfLocalVar(Args[SrcArgIndex].first)); + LValue Src = CGF.EmitLValueForFieldInitialization(SrcPtr, Field, 0); + + // Copy the aggregate. + CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType, + LHS.isVolatileQualified()); + return; + } + + // Emit the block variables for the array indices, if any. + for (unsigned I = 0, N = MemberInit->getNumArrayIndices(); I != N; ++I) + CGF.EmitLocalBlockVarDecl(*MemberInit->getArrayIndex(I)); + } + + EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit, FieldType, 0); if (!CGF.Exceptions) return; + // FIXME: If we have an array of classes w/ non-trivial destructors, + // we need to destroy in reverse order of construction along the exception + // path. const RecordType *RT = FieldType->getAs<RecordType>(); if (!RT) return; @@ -680,20 +617,13 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { // Emit the constructor prologue, i.e. the base and member // initializers. - EmitCtorPrologue(Ctor, CtorType); + EmitCtorPrologue(Ctor, CtorType, Args); // Emit the body of the statement. if (IsTryBody) EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock()); else if (Body) EmitStmt(Body); - else { - assert(Ctor->isImplicit() && "bodyless ctor not implicit"); - if (!Ctor->isDefaultConstructor()) { - assert(Ctor->isCopyConstructor()); - SynthesizeCXXCopyConstructor(Args); - } - } // Emit any cleanup blocks associated with the member or base // initializers, which includes (along the exceptional path) the @@ -708,7 +638,8 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { /// EmitCtorPrologue - This routine generates necessary code to initialize /// base classes and non-static data members belonging to this constructor. void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, - CXXCtorType CtorType) { + CXXCtorType CtorType, + FunctionArgList &Args) { const CXXRecordDecl *ClassDecl = CD->getParent(); llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> MemberInitializers; @@ -733,7 +664,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, assert(LiveTemporaries.empty() && "Should not have any live temporaries at initializer start!"); - EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I]); + EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args); } } @@ -1206,34 +1137,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, // Explicit arguments. for (; I != E; ++I) { - const VarDecl *Param = I->first; QualType ArgType = Param->getType(); // because we're passing it to itself - - // StartFunction converted the ABI-lowered parameter(s) into a - // local alloca. We need to turn that into an r-value suitable - // for EmitCall. - llvm::Value *Local = GetAddrOfLocalVar(Param); - RValue Arg; - - // For the most part, we just need to load the alloca, except: - // 1) aggregate r-values are actually pointers to temporaries, and - // 2) references to aggregates are pointers directly to the aggregate. - // I don't know why references to non-aggregates are different here. - if (ArgType->isReferenceType()) { - const ReferenceType *RefType = ArgType->getAs<ReferenceType>(); - if (hasAggregateLLVMType(RefType->getPointeeType())) - Arg = RValue::getAggregate(Local); - else - // Locals which are references to scalars are represented - // with allocas holding the pointer. - Arg = RValue::get(Builder.CreateLoad(Local)); - } else { - if (hasAggregateLLVMType(ArgType)) - Arg = RValue::getAggregate(Local); - else - Arg = RValue::get(EmitLoadOfScalar(Local, false, ArgType)); - } + RValue Arg = EmitDelegateCallArg(Param); DelegateArgs.push_back(std::make_pair(Arg, ArgType)); } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 48ae5113b3af..c9bcb1b7e043 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -64,7 +64,14 @@ llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context, // Check namespace. if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl, CompileUnit)); - + + if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) { + if (!RDecl->isDependentType()) { + llvm::DIType Ty = getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), + llvm::DIFile(CompileUnit)); + return llvm::DIDescriptor(Ty); + } + } return CompileUnit; } @@ -114,10 +121,29 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { llvm::DIFile F = DebugFactory.CreateFile(AbsFileName.getLast(), AbsFileName.getDirname(), TheCU); - DIFileCache[fname] = F.getNode(); + DIFileCache[fname] = F; return F; } + +/// getLineNumber - Get line number for the location. If location is invalid +/// then use current location. +unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { + assert (CurLoc.isValid() && "Invalid current location!"); + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); + return PLoc.getLine(); +} + +/// getColumnNumber - Get column number for the location. If location is +/// invalid then use current location. +unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) { + assert (CurLoc.isValid() && "Invalid current location!"); + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); + return PLoc.getColumn(); +} + /// CreateCompileUnit - Create new compile unit. void CGDebugInfo::CreateCompileUnit() { @@ -327,10 +353,11 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.clear(); unsigned Flags = llvm::DIType::FlagAppleBlock; + unsigned LineNo = getLineNumber(CurLoc); EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_descriptor", - Unit, 0, FieldOffset, 0, 0, Flags, - llvm::DIType(), Elements); + Unit, LineNo, FieldOffset, 0, 0, + Flags, llvm::DIType(), Elements); // Bit size, align and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(Ty); @@ -338,7 +365,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, DescTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, "", Unit, - 0, Size, Align, 0, 0, EltTy); + LineNo, Size, Align, 0, 0, EltTy); FieldOffset = 0; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); @@ -355,7 +382,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, FieldAlign = CGM.getContext().getTypeAlign(Ty); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__descriptor", Unit, - 0, FieldSize, FieldAlign, + LineNo, FieldSize, FieldAlign, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); @@ -363,14 +390,14 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_literal_generic", - Unit, 0, FieldOffset, 0, 0, Flags, - llvm::DIType(), Elements); + Unit, LineNo, FieldOffset, 0, 0, + Flags, llvm::DIType(), Elements); BlockLiteralGenericSet = true; BlockLiteralGeneric = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, "", Unit, - 0, Size, Align, 0, 0, EltTy); + LineNo, Size, Align, 0, 0, EltTy); return BlockLiteralGeneric; } @@ -382,9 +409,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, // We don't set size information, but do specify where the typedef was // declared. - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(Ty->getDecl()->getLocation()); - unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); + unsigned Line = getLineNumber(Ty->getDecl()->getLocation()); llvm::DIDescriptor TyContext = getContextDescriptor(dyn_cast<Decl>(Ty->getDecl()->getDeclContext()), @@ -430,7 +455,6 @@ void CGDebugInfo:: CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit, llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) { unsigned FieldNo = 0; - SourceManager &SM = CGM.getContext().getSourceManager(); const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); @@ -445,16 +469,8 @@ CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit, continue; // Get the location for the field. - SourceLocation FieldDefLoc = Field->getLocation(); - PresumedLoc PLoc = SM.getPresumedLoc(FieldDefLoc); - llvm::DIFile FieldDefUnit; - unsigned FieldLine = 0; - - if (!PLoc.isInvalid()) { - FieldDefUnit = getOrCreateFile(FieldDefLoc); - FieldLine = PLoc.getLine(); - } - + llvm::DIFile FieldDefUnit = getOrCreateFile(Field->getLocation()); + unsigned FieldLine = getLineNumber(Field->getLocation()); QualType FType = Field->getType(); uint64_t FieldSize = 0; unsigned FieldAlign = 0; @@ -506,7 +522,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, // Add "this" pointer. - llvm::DIArray Args = llvm::DICompositeType(FnTy.getNode()).getTypeArray(); + llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray(); assert (Args.getNumElements() && "Invalid number of arguments!"); llvm::SmallVector<llvm::DIDescriptor, 16> Elts; @@ -520,7 +536,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, Context.getPointerType(Context.getTagDeclType(Method->getParent())); llvm::DIType ThisPtrType = DebugFactory.CreateArtificialType(getOrCreateType(ThisPtr, Unit)); - TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType.getNode(); + TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; Elts.push_back(ThisPtrType); // Copy rest of the arguments. @@ -555,18 +571,9 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, if (!IsCtorOrDtor) CGM.getMangledName(MethodLinkageName, Method); - SourceManager &SM = CGM.getContext().getSourceManager(); - // Get the location for the method. - SourceLocation MethodDefLoc = Method->getLocation(); - PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc); - llvm::DIFile MethodDefUnit; - unsigned MethodLine = 0; - - if (!PLoc.isInvalid()) { - MethodDefUnit = getOrCreateFile(MethodDefLoc); - MethodLine = PLoc.getLine(); - } + llvm::DIFile MethodDefUnit = getOrCreateFile(Method->getLocation()); + unsigned MethodLine = getLineNumber(Method->getLocation()); // Collect virtual method info. llvm::DIType ContainingType; @@ -597,7 +604,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, // Don't cache ctors or dtors since we have to emit multiple functions for // a single ctor or dtor. if (!IsCtorOrDtor && Method->isThisDeclarationADefinition()) - SPCache[Method] = llvm::WeakVH(SP.getNode()); + SPCache[Method] = llvm::WeakVH(SP); return SP; } @@ -741,16 +748,9 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, Tag = llvm::dwarf::DW_TAG_class_type; } - SourceManager &SM = CGM.getContext().getSourceManager(); - // Get overall information about the record type for the debug info. - PresumedLoc PLoc = SM.getPresumedLoc(RD->getLocation()); - llvm::DIFile DefUnit; - unsigned Line = 0; - if (!PLoc.isInvalid()) { - DefUnit = getOrCreateFile(RD->getLocation()); - Line = PLoc.getLine(); - } + llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); + unsigned Line = getLineNumber(RD->getLocation()); // Records and classes and unions can all be recursive. To handle them, we // first generate a debug descriptor for the struct as a forward declaration. @@ -774,13 +774,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, if (!RD->getDefinition()) return FwdDecl; - llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); + llvm::MDNode *MN = FwdDecl; + llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN; // Otherwise, insert it into the TypeCache so that recursive uses will find // it. - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; // Push the struct on region stack. - RegionStack.push_back(FwdDecl.getNode()); - RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl.getNode()); + RegionStack.push_back(FwdDeclNode); + RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl); // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; @@ -799,9 +800,9 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) ContainingType = - getOrCreateType(QualType(PBase->getTypeForDecl(), 0), Unit).getNode(); + getOrCreateType(QualType(PBase->getTypeForDecl(), 0), Unit); else if (CXXDecl->isDynamicClass()) - ContainingType = FwdDecl.getNode(); + ContainingType = FwdDecl; } llvm::DIArray Elements = @@ -829,24 +830,26 @@ 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()); + RegionMap[RD] = llvm::WeakVH(RealDecl); return RealDecl; } +/// CreateType - get objective-c object type. +llvm::DIType CGDebugInfo::CreateType(const ObjCObjectType *Ty, + llvm::DIFile Unit) { + // Ignore protocols. + return getOrCreateType(Ty->getBaseType(), Unit); +} + /// CreateType - get objective-c interface type. llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DIFile Unit) { ObjCInterfaceDecl *ID = Ty->getDecl(); - unsigned Tag = llvm::dwarf::DW_TAG_structure_type; - SourceManager &SM = CGM.getContext().getSourceManager(); // Get overall information about the record type for the debug info. llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation()); - PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation()); - unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); - - + unsigned Line = getLineNumber(ID->getLocation()); unsigned RuntimeLang = TheCU.getLanguage(); // To handle recursive interface, we @@ -865,13 +868,14 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (ID->isForwardDecl()) return FwdDecl; - llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); + llvm::MDNode *MN = FwdDecl; + llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN; // Otherwise, insert it into the TypeCache so that recursive uses will find // it. - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; // Push the struct on region stack. - RegionStack.push_back(FwdDecl.getNode()); - RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl.getNode()); + RegionStack.push_back(FwdDeclNode); + RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl); // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; @@ -902,12 +906,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, continue; // Get the location for the field. - SourceLocation FieldDefLoc = Field->getLocation(); - llvm::DIFile FieldDefUnit = getOrCreateFile(FieldDefLoc); - PresumedLoc PLoc = SM.getPresumedLoc(FieldDefLoc); - unsigned FieldLine = PLoc.isInvalid() ? 0 : PLoc.getLine(); - - + llvm::DIFile FieldDefUnit = getOrCreateFile(Field->getLocation()); + unsigned FieldLine = getLineNumber(Field->getLocation()); QualType FType = Field->getType(); uint64_t FieldSize = 0; unsigned FieldAlign = 0; @@ -962,7 +962,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()); + RegionMap[ID] = llvm::WeakVH(RealDecl); return RealDecl; } @@ -985,12 +985,8 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::DIArray EltArray = DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size()); - SourceLocation DefLoc = ED->getLocation(); - llvm::DIFile DefUnit = getOrCreateFile(DefLoc); - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); - unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); - + llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); + unsigned Line = getLineNumber(ED->getLocation()); // Size and align of the type. uint64_t Size = 0; @@ -1152,15 +1148,12 @@ static QualType UnwrapTypeForDebugInfo(QualType T) { case Type::Decltype: T = cast<DecltypeType>(T)->getUnderlyingType(); break; - case Type::QualifiedName: - T = cast<QualifiedNameType>(T)->getNamedType(); + case Type::Elaborated: + T = cast<ElaboratedType>(T)->getNamedType(); break; case Type::SubstTemplateTypeParm: T = cast<SubstTemplateTypeParmType>(T)->getReplacementType(); break; - case Type::Elaborated: - T = cast<ElaboratedType>(T)->getUnderlyingType(); - break; } assert(T != LastT && "Type unwrapping failed to unwrap!"); @@ -1194,7 +1187,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIType Res = CreateTypeNode(Ty, Unit); // And update the type cache. - TypeCache[Ty.getAsOpaquePtr()] = Res.getNode(); + TypeCache[Ty.getAsOpaquePtr()] = Res; return Res; } @@ -1224,6 +1217,8 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, return CreateType(cast<VectorType>(Ty), Unit); case Type::ObjCObjectPointer: return CreateType(cast<ObjCObjectPointerType>(Ty), Unit); + case Type::ObjCObject: + return CreateType(cast<ObjCObjectType>(Ty), Unit); case Type::ObjCInterface: return CreateType(cast<ObjCInterfaceType>(Ty), Unit); case Type::Builtin: return CreateType(cast<BuiltinType>(Ty), Unit); @@ -1251,7 +1246,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::TemplateSpecialization: case Type::Elaborated: - case Type::QualifiedName: case Type::SubstTemplateTypeParm: case Type::TypeOfExpr: case Type::TypeOf: @@ -1304,9 +1298,10 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, FI = SPCache.find(FD); if (FI != SPCache.end()) { llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(FI->second)); - if (SP.isSubprogram() && llvm::DISubprogram(SP.getNode()).isDefinition()) { - RegionStack.push_back(SP.getNode()); - RegionMap[D] = llvm::WeakVH(SP.getNode()); + if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) { + llvm::MDNode *SPN = SP; + RegionStack.push_back(SPN); + RegionMap[D] = llvm::WeakVH(SP); return; } } @@ -1325,8 +1320,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, // Usually, CurLoc points to the left bracket location of compound // statement representing function body. llvm::DIFile Unit = getOrCreateFile(CurLoc); - SourceManager &SM = CGM.getContext().getSourceManager(); - unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine(); + unsigned LineNo = getLineNumber(CurLoc); llvm::DISubprogram SP = DebugFactory.CreateSubprogram(Unit, Name, Name, LinkageName, Unit, LineNo, @@ -1334,8 +1328,9 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, Fn->hasInternalLinkage(), true/*definition*/); // Push function on region stack. - RegionStack.push_back(SP.getNode()); - RegionMap[D] = llvm::WeakVH(SP.getNode()); + llvm::MDNode *SPN = SP; + RegionStack.push_back(SPN); + RegionMap[D] = llvm::WeakVH(SP); } @@ -1355,27 +1350,23 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { // Update last state. PrevLoc = CurLoc; - // Get the appropriate compile unit. - llvm::DIFile Unit = getOrCreateFile(CurLoc); - PresumedLoc PLoc = SM.getPresumedLoc(CurLoc); - llvm::MDNode *Scope = RegionStack.back(); - Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(PLoc.getLine(), - PLoc.getColumn(), + Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc), + getColumnNumber(CurLoc), Scope)); } /// EmitRegionStart- Constructs the debug code for entering a declarative /// region - "llvm.dbg.region.start.". void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) { - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(CurLoc); llvm::DIDescriptor D = DebugFactory.CreateLexicalBlock(RegionStack.empty() ? llvm::DIDescriptor() : llvm::DIDescriptor(RegionStack.back()), - PLoc.getLine(), PLoc.getColumn()); - RegionStack.push_back(D.getNode()); + getLineNumber(CurLoc), + getColumnNumber(CurLoc)); + llvm::MDNode *DN = D; + RegionStack.push_back(DN); } /// EmitRegionEnd - Constructs the debug code for exiting a declarative @@ -1473,20 +1464,14 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, else Ty = getOrCreateType(VD->getType(), Unit); + // If there is not any debug info for type then do not emit debug info + // for this variable. + if (!Ty) + return; + // Get location information. - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation()); - unsigned Line = 0; - unsigned Column = 0; - if (PLoc.isInvalid()) - PLoc = SM.getPresumedLoc(CurLoc); - if (PLoc.isValid()) { - Line = PLoc.getLine(); - Column = PLoc.getColumn(); - Unit = getOrCreateFile(CurLoc); - } else { - Unit = llvm::DIFile(); - } + unsigned Line = getLineNumber(VD->getLocation()); + unsigned Column = getColumnNumber(VD->getLocation()); // Create the descriptor for the variable. llvm::DIVariable D = @@ -1520,13 +1505,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, Ty = getOrCreateType(VD->getType(), Unit); // Get location information. - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation()); - unsigned Line = 0; - if (!PLoc.isInvalid()) - Line = PLoc.getLine(); - else - Unit = llvm::DIFile(); + unsigned Line = getLineNumber(VD->getLocation()); + unsigned Column = getColumnNumber(VD->getLocation()); CharUnits offset = CGF->BlockDecls[VD]; llvm::SmallVector<llvm::Value *, 9> addr; @@ -1558,7 +1538,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock()); llvm::MDNode *Scope = RegionStack.back(); - Call->setDebugLoc(llvm::DebugLoc::get(Line, PLoc.getColumn(), Scope)); + Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); } void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, @@ -1588,9 +1568,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, // Create global variable debug descriptor. llvm::DIFile Unit = getOrCreateFile(D->getLocation()); - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(D->getLocation()); - unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); + unsigned LineNo = getLineNumber(D->getLocation()); QualType T = D->getType(); if (T->isIncompleteArrayType()) { @@ -1605,11 +1583,13 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, ArrayType::Normal, 0); } llvm::StringRef DeclName = D->getName(); + llvm::StringRef LinkageName; + if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext())) + LinkageName = Var->getName(); llvm::DIDescriptor DContext = getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()), Unit); - DebugFactory.CreateGlobalVariable(DContext, DeclName, - DeclName, llvm::StringRef(), Unit, LineNo, - getOrCreateType(T, Unit), + DebugFactory.CreateGlobalVariable(DContext, DeclName, DeclName, LinkageName, + Unit, LineNo, getOrCreateType(T, Unit), Var->hasInternalLinkage(), true/*definition*/, Var); } @@ -1619,9 +1599,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, ObjCInterfaceDecl *ID) { // Create global variable debug descriptor. llvm::DIFile Unit = getOrCreateFile(ID->getLocation()); - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation()); - unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); + unsigned LineNo = getLineNumber(ID->getLocation()); llvm::StringRef Name = ID->getName(); @@ -1654,15 +1632,13 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl, if (I != NameSpaceCache.end()) return llvm::DINameSpace(cast<llvm::MDNode>(I->second)); - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(NSDecl->getLocation()); - unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); + unsigned LineNo = getLineNumber(NSDecl->getLocation()); llvm::DIDescriptor Context = getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()), Unit); llvm::DINameSpace NS = DebugFactory.CreateNameSpace(Context, NSDecl->getName(), - llvm::DIFile(Unit.getNode()), LineNo); - NameSpaceCache[NSDecl] = llvm::WeakVH(NS.getNode()); + llvm::DIFile(Unit), LineNo); + NameSpaceCache[NSDecl] = llvm::WeakVH(NS); return NS; } diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index c16379aca34c..620a5f2f8480 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -80,6 +80,7 @@ class CGDebugInfo { llvm::DIType CreateType(const TagType *Ty, llvm::DIFile F); llvm::DIType CreateType(const RecordType *Ty, llvm::DIFile F); llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F); llvm::DIType CreateType(const EnumType *Ty, llvm::DIFile F); llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F); llvm::DIType CreateType(const ArrayType *Ty, llvm::DIFile F); @@ -208,6 +209,13 @@ private: /// getVTableName - Get vtable name for the given Class. llvm::StringRef getVTableName(const CXXRecordDecl *Decl); + /// getLineNumber - Get line number for the location. If location is invalid + /// then use current location. + unsigned getLineNumber(SourceLocation Loc); + + /// getColumnNumber - Get column number for the location. If location is + /// invalid then use current location. + unsigned getColumnNumber(SourceLocation Loc); }; } // namespace CodeGen } // namespace clang diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 48198ff5761b..07edca0f5fef 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -114,14 +114,14 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { llvm::GlobalValue::LinkageTypes Linkage = llvm::GlobalValue::InternalLinkage; - // If this is a static declaration inside an inline function, it must have - // weak linkage so that the linker will merge multiple definitions of it. - if (getContext().getLangOptions().CPlusPlus) { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl)) { - if (FD->isInlined()) - Linkage = llvm::GlobalValue::WeakAnyLinkage; - } - } + // If the function definition has some sort of weak linkage, its + // static variables should also be weak so that they get properly + // uniqued. We can't do this in C, though, because there's no + // standard way to agree on which variables are the same (i.e. + // there's no mangling). + if (getContext().getLangOptions().CPlusPlus) + if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage())) + Linkage = CurFn->getLinkage(); return EmitStaticBlockVarDecl(D, Linkage); } @@ -239,8 +239,6 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, // Store into LocalDeclMap before generating initializer to handle // circular references. DMEntry = GV; - if (getContext().getLangOptions().CPlusPlus) - CGM.setStaticLocalDeclAddress(&D, GV); // We can't have a VLA here, but we can have a pointer to a VLA, // even though that doesn't really make any sense. @@ -269,6 +267,9 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, if (D.hasAttr<UsedAttr>()) CGM.AddUsedGlobal(GV); + if (getContext().getLangOptions().CPlusPlus) + CGM.setStaticLocalDeclAddress(&D, GV); + // We may have to cast the constant because of the initializer // mismatch above. // @@ -398,16 +399,20 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { CharUnits Align = CharUnits::Zero(); bool IsSimpleConstantInitializer = false; + bool NRVO = false; + llvm::Value *NRVOFlag = 0; llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { - + NRVO = getContext().getLangOptions().ElideConstructors && + D.isNRVOVariable(); // If this value is an array or struct, is POD, and if the initializer is - // a staticly determinable constant, try to optimize it. + // a staticly determinable constant, try to optimize it (unless the NRVO + // is already optimizing this). if (D.getInit() && !isByRef && (Ty->isArrayType() || Ty->isRecordType()) && Ty->isPODType() && - D.getInit()->isConstantInitializer(getContext())) { + D.getInit()->isConstantInitializer(getContext()) && !NRVO) { // If this variable is marked 'const', emit the value as a global. if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstant(getContext())) { @@ -418,19 +423,44 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { IsSimpleConstantInitializer = true; } - // A normal fixed sized variable becomes an alloca in the entry block. + // A normal fixed sized variable becomes an alloca in the entry block, + // unless it's an NRVO variable. const llvm::Type *LTy = ConvertTypeForMem(Ty); - if (isByRef) - LTy = BuildByRefType(&D); - llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); - Alloc->setName(D.getNameAsString()); - - Align = getContext().getDeclAlign(&D); - if (isByRef) - Align = std::max(Align, - CharUnits::fromQuantity(Target.getPointerAlign(0) / 8)); - Alloc->setAlignment(Align.getQuantity()); - DeclPtr = Alloc; + + if (NRVO) { + // The named return value optimization: allocate this variable in the + // return slot, so that we can elide the copy when returning this + // variable (C++0x [class.copy]p34). + DeclPtr = ReturnValue; + + if (const RecordType *RecordTy = Ty->getAs<RecordType>()) { + if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) { + // Create a flag that is used to indicate when the NRVO was applied + // to this variable. Set it to zero to indicate that NRVO was not + // applied. + const llvm::Type *BoolTy = llvm::Type::getInt1Ty(VMContext); + llvm::Value *Zero = llvm::ConstantInt::get(BoolTy, 0); + NRVOFlag = CreateTempAlloca(BoolTy, "nrvo"); + Builder.CreateStore(Zero, NRVOFlag); + + // Record the NRVO flag for this variable. + NRVOFlags[&D] = NRVOFlag; + } + } + } else { + if (isByRef) + LTy = BuildByRefType(&D); + + llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); + Alloc->setName(D.getNameAsString()); + + Align = getContext().getDeclAlign(&D); + if (isByRef) + Align = std::max(Align, + CharUnits::fromQuantity(Target.getPointerAlign(0) / 8)); + Alloc->setAlignment(Align.getQuantity()); + DeclPtr = Alloc; + } } else { // Targets that don't support recursion emit locals as globals. const char *Class = @@ -645,13 +675,15 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { while (const ArrayType *Array = getContext().getAsArrayType(DtorTy)) DtorTy = getContext().getBaseElementType(Array); if (const RecordType *RT = DtorTy->getAs<RecordType>()) - if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { - llvm::Value *Loc = DeclPtr; - if (isByRef) - Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), - D.getNameAsString()); - + if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { if (!ClassDecl->hasTrivialDestructor()) { + // Note: We suppress the destructor call when the corresponding NRVO + // flag has been set. + llvm::Value *Loc = DeclPtr; + if (isByRef) + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); + const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext()); assert(D && "EmitLocalBlockVarDecl - destructor is nul"); @@ -680,13 +712,27 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { } } else { { + // Normal destruction. DelayedCleanupBlock Scope(*this); + + if (NRVO) { + // If we exited via NRVO, we skip the destructor call. + llvm::BasicBlock *NoNRVO = createBasicBlock("nrvo.unused"); + Builder.CreateCondBr(Builder.CreateLoad(NRVOFlag, "nrvo.val"), + Scope.getCleanupExitBlock(), + NoNRVO); + EmitBlock(NoNRVO); + } + + // We don't call the destructor along the normal edge if we're + // applying the NRVO. EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Loc); // Make sure to jump to the exit block. EmitBranch(Scope.getCleanupExitBlock()); } + if (Exceptions) { EHCleanupBlock Cleanup(*this); EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 6afa53868ecc..f94ddd988662 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -13,6 +13,8 @@ #include "CodeGenFunction.h" #include "clang/CodeGen/CodeGenOptions.h" +#include "llvm/Intrinsics.h" + using namespace clang; using namespace CodeGen; @@ -22,7 +24,6 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, assert(!D.getType()->isReferenceType() && "Should not call EmitDeclInit on a reference!"); - CodeGenModule &CGM = CGF.CGM; ASTContext &Context = CGF.getContext(); const Expr *Init = D.getInit(); @@ -36,41 +37,52 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); } else { CGF.EmitAggExpr(Init, DeclPtr, isVolatile); - - // Avoid generating destructor(s) for initialized objects. - if (!isa<CXXConstructExpr>(Init)) - return; - - const ConstantArrayType *Array = Context.getAsConstantArrayType(T); - if (Array) - T = Context.getBaseElementType(Array); - - const RecordType *RT = T->getAs<RecordType>(); - if (!RT) - return; - - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialDestructor()) - return; - - CXXDestructorDecl *Dtor = RD->getDestructor(Context); - - llvm::Constant *DtorFn; - if (Array) { - DtorFn = - CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor, - Array, - DeclPtr); - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - DeclPtr = llvm::Constant::getNullValue(Int8PtrTy); - } else - DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); - - CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); } } +static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, + llvm::Constant *DeclPtr) { + CodeGenModule &CGM = CGF.CGM; + ASTContext &Context = CGF.getContext(); + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + if (!CGF.hasAggregateLLVMType(T) || T->isAnyComplexType()) + return; + + // Avoid generating destructor(s) for initialized objects. + if (!isa<CXXConstructExpr>(Init)) + return; + + const ConstantArrayType *Array = Context.getAsConstantArrayType(T); + if (Array) + T = Context.getBaseElementType(Array); + + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return; + + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialDestructor()) + return; + + CXXDestructorDecl *Dtor = RD->getDestructor(Context); + + llvm::Constant *DtorFn; + if (Array) { + DtorFn = + CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor, + Array, + DeclPtr); + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + DeclPtr = llvm::Constant::getNullValue(Int8PtrTy); + } else + DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); + + CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); +} + void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr) { @@ -79,6 +91,7 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, if (!T->isReferenceType()) { EmitDeclInit(*this, D, DeclPtr); + EmitDeclDestroy(*this, D, DeclPtr); return; } if (Init->isLvalue(getContext()) == Expr::LV_Valid) { @@ -310,7 +323,10 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, EmitBlock(InitCheckBlock); - if (ThreadsafeStatics) { + // Variables used when coping with thread-safe statics and exceptions. + llvm::BasicBlock *SavedLandingPad = 0; + llvm::BasicBlock *LandingPad = 0; + if (ThreadsafeStatics) { // Call __cxa_guard_acquire. V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable); @@ -319,14 +335,13 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"), InitBlock, EndBlock); - EmitBlock(InitBlock); - if (Exceptions) { - EHCleanupBlock Cleanup(*this); - - // Call __cxa_guard_abort. - Builder.CreateCall(getGuardAbortFn(*this), GuardVariable); + SavedLandingPad = getInvokeDest(); + LandingPad = createBasicBlock("guard.lpad"); + setInvokeDest(LandingPad); } + + EmitBlock(InitBlock); } if (D.getType()->isReferenceType()) { @@ -342,12 +357,68 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, if (ThreadsafeStatics) { // Call __cxa_guard_release. - Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable); + Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable); } else { llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1); Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy)); } + // Register the call to the destructor. + if (!D.getType()->isReferenceType()) + EmitDeclDestroy(*this, D, GV); + + if (ThreadsafeStatics && Exceptions) { + // If an exception is thrown during initialization, call __cxa_guard_abort + // along the exceptional edge. + EmitBranch(EndBlock); + + // Construct the landing pad. + EmitBlock(LandingPad); + + // Personality function and LLVM intrinsics. + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + + // Exception object + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + + // Call the selector function. + const llvm::PointerType *PtrToInt8Ty + = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext)); + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::Value* SelectorArgs[3] = { Exc, Personality, Null }; + Builder.CreateCall(llvm_eh_selector, SelectorArgs, SelectorArgs + 3, + "selector"); + Builder.CreateStore(Exc, RethrowPtr); + + // Call __cxa_guard_abort along the exceptional edge. + Builder.CreateCall(getGuardAbortFn(*this), GuardVariable); + + setInvokeDest(SavedLandingPad); + + // Rethrow the current exception. + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + Builder.CreateInvoke(getUnwindResumeOrRethrowFn(), Cont, + getInvokeDest(), + Builder.CreateLoad(RethrowPtr)); + EmitBlock(Cont); + } else + Builder.CreateCall(getUnwindResumeOrRethrowFn(), + Builder.CreateLoad(RethrowPtr)); + + Builder.CreateUnreachable(); + } + EmitBlock(EndBlock); } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index c1d05bf233b2..ddc1c7743344 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -100,17 +100,17 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); } -static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); +llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); std::vector<const llvm::Type*> Args(1, Int8PtrTy); const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, + llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Args, false); - if (CGF.CGM.getLangOptions().SjLjExceptions) - return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); - return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); + if (CGM.getLangOptions().SjLjExceptions) + return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); + return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); } static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { @@ -119,7 +119,29 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); - return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev"); + return CGF.CGM.CreateRuntimeFunction(FTy, + CGF.CGM.getLangOptions().CPlusPlus ? "_ZSt9terminatev" : "abort"); +} + +static llvm::Constant *getPersonalityFn(CodeGenModule &CGM) { + const char *PersonalityFnName = "__gcc_personality_v0"; + LangOptions Opts = CGM.getLangOptions(); + if (Opts.CPlusPlus) + PersonalityFnName = "__gxx_personality_v0"; + else if (Opts.ObjC1) { + if (Opts.NeXTRuntime) { + if (Opts.ObjCNonFragileABI) + PersonalityFnName = "__gcc_personality_v0"; + } else + PersonalityFnName = "__gnu_objc_personality_v0"; + } + + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty( + CGM.getLLVMContext()), + true), + PersonalityFnName); + return llvm::ConstantExpr::getBitCast(Personality, CGM.PtrToInt8Ty); } // Emits an exception expression into the given location. This @@ -324,12 +346,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { if (!Proto->hasExceptionSpec()) return; - llvm::Constant *Personality = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty - (VMContext), - true), - "__gxx_personality_v0"); - Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Constant *Personality = getPersonalityFn(CGM); llvm::Value *llvm_eh_exception = CGM.getIntrinsic(llvm::Intrinsic::eh_exception); llvm::Value *llvm_eh_selector = @@ -397,7 +414,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { if (Proto->getNumExceptions()) { EmitBlock(Unwind); - Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateCall(getUnwindResumeOrRethrowFn(), Builder.CreateLoad(RethrowPtr)); Builder.CreateUnreachable(); } @@ -444,12 +461,7 @@ CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S) { void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, CXXTryStmtInfo TryInfo) { // Pointer to the personality function - llvm::Constant *Personality = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty - (VMContext), - true), - "__gxx_personality_v0"); - Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Constant *Personality = getPersonalityFn(CGM); llvm::Value *llvm_eh_exception = CGM.getIntrinsic(llvm::Intrinsic::eh_exception); llvm::Value *llvm_eh_selector = @@ -631,12 +643,12 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, // here. if (getInvokeDest()) { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); - Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont, + Builder.CreateInvoke(getUnwindResumeOrRethrowFn(), Cont, getInvokeDest(), Builder.CreateLoad(RethrowPtr)); EmitBlock(Cont); } else - Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateCall(getUnwindResumeOrRethrowFn(), Builder.CreateLoad(RethrowPtr)); Builder.CreateUnreachable(); @@ -654,12 +666,7 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { // The libstdc++ personality function. // TODO: generalize to work with other libraries. - llvm::Constant *Personality = - CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty - (CGF.VMContext), - true), - "__gxx_personality_v0"); - Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty); + llvm::Constant *Personality = getPersonalityFn(CGF.CGM); // %exception = call i8* @llvm.eh.exception() // Magic intrinsic which tells gives us a handle to the caught @@ -687,11 +694,11 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { // Rethrow the exception. if (CGF.getInvokeDest()) { llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); - CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont, + CGF.Builder.CreateInvoke(CGF.getUnwindResumeOrRethrowFn(), Cont, CGF.getInvokeDest(), Exc); CGF.EmitBlock(Cont); } else - CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc); + CGF.Builder.CreateCall(CGF.getUnwindResumeOrRethrowFn(), Exc); CGF.Builder.CreateUnreachable(); // Resume inserting where we started, but put the new cleanup @@ -715,12 +722,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { llvm::BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint(); Builder.ClearInsertionPoint(); - llvm::Constant *Personality = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty - (VMContext), - true), - "__gxx_personality_v0"); - Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Constant *Personality = getPersonalityFn(CGM); llvm::Value *llvm_eh_exception = CGM.getIntrinsic(llvm::Intrinsic::eh_exception); llvm::Value *llvm_eh_selector = diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 9ade916f42b7..d67618bfca35 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -135,6 +135,39 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E, } } +/// \brief An adjustment to be made to the temporary created when emitting a +/// reference binding, which accesses a particular subobject of that temporary. +struct SubobjectAdjustment { + enum { DerivedToBaseAdjustment, FieldAdjustment } Kind; + + union { + struct { + const CXXBaseSpecifierArray *BasePath; + const CXXRecordDecl *DerivedClass; + } DerivedToBase; + + struct { + FieldDecl *Field; + unsigned CVRQualifiers; + } Field; + }; + + SubobjectAdjustment(const CXXBaseSpecifierArray *BasePath, + const CXXRecordDecl *DerivedClass) + : Kind(DerivedToBaseAdjustment) + { + DerivedToBase.BasePath = BasePath; + DerivedToBase.DerivedClass = DerivedClass; + } + + SubobjectAdjustment(FieldDecl *Field, unsigned CVRQualifiers) + : Kind(FieldAdjustment) + { + this->Field.Field = Field; + this->Field.CVRQualifiers = CVRQualifiers; + } +}; + RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, bool IsInitializer) { bool ShouldDestroyTemporaries = false; @@ -174,19 +207,46 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, PopCXXTemporary(); } } else { - const CXXBaseSpecifierArray *BasePath = 0; - const CXXRecordDecl *DerivedClassDecl = 0; + QualType ResultTy = E->getType(); - if (const CastExpr *CE = - dyn_cast<CastExpr>(E->IgnoreParenNoopCasts(getContext()))) { - if (CE->getCastKind() == CastExpr::CK_DerivedToBase) { - E = CE->getSubExpr(); - - BasePath = &CE->getBasePath(); - DerivedClassDecl = - cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); + llvm::SmallVector<SubobjectAdjustment, 2> Adjustments; + do { + if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + E = PE->getSubExpr(); + continue; + } + + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if ((CE->getCastKind() == CastExpr::CK_DerivedToBase || + CE->getCastKind() == CastExpr::CK_UncheckedDerivedToBase) && + E->getType()->isRecordType()) { + E = CE->getSubExpr(); + CXXRecordDecl *Derived + = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); + Adjustments.push_back(SubobjectAdjustment(&CE->getBasePath(), + Derived)); + continue; + } + + if (CE->getCastKind() == CastExpr::CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + if (ME->getBase()->isLvalue(getContext()) != Expr::LV_Valid && + ME->getBase()->getType()->isRecordType()) { + if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { + E = ME->getBase(); + Adjustments.push_back(SubobjectAdjustment(Field, + E->getType().getCVRQualifiers())); + continue; + } + } } - } + + // Nothing changed. + break; + } while (true); Val = EmitAnyExprToTemp(E, /*IsAggLocVolatile=*/false, IsInitializer); @@ -225,13 +285,47 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, } } - // Check if need to perform the derived-to-base cast. - if (BasePath) { - llvm::Value *Derived = Val.getAggregateAddr(); - llvm::Value *Base = - GetAddressOfBaseClass(Derived, DerivedClassDecl, *BasePath, - /*NullCheckValue=*/false); - return RValue::get(Base); + // Check if need to perform derived-to-base casts and/or field accesses, to + // get from the temporary object we created (and, potentially, for which we + // extended the lifetime) to the subobject we're binding the reference to. + if (!Adjustments.empty()) { + llvm::Value *Object = Val.getAggregateAddr(); + for (unsigned I = Adjustments.size(); I != 0; --I) { + SubobjectAdjustment &Adjustment = Adjustments[I-1]; + switch (Adjustment.Kind) { + case SubobjectAdjustment::DerivedToBaseAdjustment: + Object = GetAddressOfBaseClass(Object, + Adjustment.DerivedToBase.DerivedClass, + *Adjustment.DerivedToBase.BasePath, + /*NullCheckValue=*/false); + break; + + case SubobjectAdjustment::FieldAdjustment: { + unsigned CVR = Adjustment.Field.CVRQualifiers; + LValue LV = EmitLValueForField(Object, Adjustment.Field.Field, CVR); + if (LV.isSimple()) { + Object = LV.getAddress(); + break; + } + + // For non-simple lvalues, we actually have to create a copy of + // the object we're binding to. + QualType T = Adjustment.Field.Field->getType().getNonReferenceType() + .getUnqualifiedType(); + Object = CreateTempAlloca(ConvertType(T), "lv"); + EmitStoreThroughLValue(EmitLoadOfLValue(LV, T), + LValue::MakeAddr(Object, + Qualifiers::fromCVRMask(CVR)), + T); + break; + } + } + } + + const llvm::Type *ResultPtrTy + = llvm::PointerType::get(ConvertType(ResultTy), 0); + Object = Builder.CreateBitCast(Object, ResultPtrTy, "temp"); + return RValue::get(Object); } } @@ -309,8 +403,7 @@ EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal); if (!isa<llvm::FunctionType>(PT->getElementType())) { QualType PTEE = ValTy->getPointeeType(); - if (const ObjCInterfaceType *OIT = - dyn_cast<ObjCInterfaceType>(PTEE)) { + if (const ObjCObjectType *OIT = PTEE->getAs<ObjCObjectType>()) { // Handle interface types, which are not represented with a concrete // type. int size = getContext().getTypeSize(OIT) / 8; @@ -1371,8 +1464,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { llvm::ConstantInt::get(Idx->getType(), BaseTypeSize.getQuantity())); Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx"); - } else if (const ObjCInterfaceType *OIT = - dyn_cast<ObjCInterfaceType>(E->getType())) { + } else if (const ObjCObjectType *OIT = + E->getType()->getAs<ObjCObjectType>()) { llvm::Value *InterfaceSize = llvm::ConstantInt::get(Idx->getType(), getContext().getTypeSizeInChars(OIT).getQuantity()); @@ -1530,6 +1623,35 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, Field->getType().getCVRQualifiers()|CVRQualifiers); } +/// EmitLValueForAnonRecordField - Given that the field is a member of +/// an anonymous struct or union buried inside a record, and given +/// that the base value is a pointer to the enclosing record, derive +/// an lvalue for the ultimate field. +LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue, + const FieldDecl *Field, + unsigned CVRQualifiers) { + llvm::SmallVector<const FieldDecl *, 8> Path; + Path.push_back(Field); + + while (Field->getParent()->isAnonymousStructOrUnion()) { + const ValueDecl *VD = Field->getParent()->getAnonymousStructOrUnionObject(); + if (!isa<FieldDecl>(VD)) break; + Field = cast<FieldDecl>(VD); + Path.push_back(Field); + } + + llvm::SmallVectorImpl<const FieldDecl*>::reverse_iterator + I = Path.rbegin(), E = Path.rend(); + while (true) { + LValue LV = EmitLValueForField(BaseValue, *I, CVRQualifiers); + if (++I == E) return LV; + + assert(LV.isSimple()); + BaseValue = LV.getAddress(); + CVRQualifiers |= LV.getVRQualifiers(); + } +} + LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, const FieldDecl* Field, unsigned CVRQualifiers) { @@ -1670,7 +1792,17 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { MakeQualifiers(E->getType())); } - case CastExpr::CK_NoOp: + case CastExpr::CK_NoOp: { + LValue LV = EmitLValue(E->getSubExpr()); + if (LV.isPropertyRef()) { + QualType QT = E->getSubExpr()->getType(); + RValue RV = EmitLoadOfPropertyRefLValue(LV, QT); + assert(!RV.isScalar() && "EmitCastLValue - scalar cast of property ref"); + llvm::Value *V = RV.getAggregateAddr(); + return LValue::MakeAddr(V, MakeQualifiers(QT)); + } + return LV; + } case CastExpr::CK_ConstructorConversion: case CastExpr::CK_UserDefinedConversion: case CastExpr::CK_AnyPointerToObjCPointerCast: @@ -1724,7 +1856,7 @@ LValue CodeGenFunction::EmitNullInitializationLValue( const CXXZeroInitValueExpr *E) { QualType Ty = E->getType(); LValue LV = LValue::MakeAddr(CreateMemTemp(Ty), MakeQualifiers(Ty)); - EmitMemSetToZero(LV.getAddress(), Ty); + EmitNullInitialization(LV.getAddress(), Ty); return LV; } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index d1b0dff11e5a..a4e64fb3d638 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -37,6 +37,16 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { bool IgnoreResult; bool IsInitializer; bool RequiresGCollection; + + ReturnValueSlot getReturnValueSlot() const { + // If the destination slot requires garbage collection, we can't + // use the real return value slot, because we have to use the GC + // API. + if (RequiresGCollection) return ReturnValueSlot(); + + return ReturnValueSlot(DestPtr, VolatileDest); + } + public: AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool v, bool ignore, bool isinit, bool requiresGCollection) @@ -58,6 +68,10 @@ public: void EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore = false); void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false); + void EmitGCMove(const Expr *E, RValue Src); + + bool TypeRequiresGCollection(QualType T); + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// @@ -137,6 +151,39 @@ void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) { EmitFinalDestCopy(E, LV); } +/// \brief True if the given aggregate type requires special GC API calls. +bool AggExprEmitter::TypeRequiresGCollection(QualType T) { + // Only record types have members that might require garbage collection. + const RecordType *RecordTy = T->getAs<RecordType>(); + if (!RecordTy) return false; + + // Don't mess with non-trivial C++ types. + RecordDecl *Record = RecordTy->getDecl(); + if (isa<CXXRecordDecl>(Record) && + (!cast<CXXRecordDecl>(Record)->hasTrivialCopyConstructor() || + !cast<CXXRecordDecl>(Record)->hasTrivialDestructor())) + return false; + + // Check whether the type has an object member. + return Record->hasObjectMember(); +} + +/// \brief Perform the final move to DestPtr if RequiresGCollection is set. +/// +/// The idea is that you do something like this: +/// RValue Result = EmitSomething(..., getReturnValueSlot()); +/// EmitGCMove(E, Result); +/// If GC doesn't interfere, this will cause the result to be emitted +/// directly into the return value slot. If GC does interfere, a final +/// move will be performed. +void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { + if (!RequiresGCollection) return; + + CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr, + Src.getAggregateAddr(), + E->getType()); +} + /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired. void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { assert(Src.isAggregate() && "value must be aggregate value!"); @@ -178,7 +225,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) { //===----------------------------------------------------------------------===// void AggExprEmitter::VisitCastExpr(CastExpr *E) { - if (!DestPtr) { + if (!DestPtr && E->getCastKind() != CastExpr::CK_Dynamic) { Visit(E->getSubExpr()); return; } @@ -186,6 +233,20 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { switch (E->getCastKind()) { default: assert(0 && "Unhandled cast kind!"); + case CastExpr::CK_Dynamic: { + assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?"); + LValue LV = CGF.EmitCheckedLValue(E->getSubExpr()); + // FIXME: Do we also need to handle property references here? + if (LV.isSimple()) + CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E)); + else + CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast"); + + if (DestPtr) + CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination"); + break; + } + case CastExpr::CK_ToUnion: { // GCC union extension QualType PtrTy = @@ -198,6 +259,14 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { break; } + case CastExpr::CK_DerivedToBase: + case CastExpr::CK_BaseToDerived: + case CastExpr::CK_UncheckedDerivedToBase: { + assert(0 && "cannot perform hierarchy conversion in EmitAggExpr: " + "should have been unpacked before we got here"); + break; + } + // FIXME: Remove the CK_Unknown check here. case CastExpr::CK_Unknown: case CastExpr::CK_NoOp: @@ -282,31 +351,24 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) { return; } - // If the struct doesn't require GC, we can just pass the destination - // directly to EmitCall. - if (!RequiresGCollection) { - CGF.EmitCallExpr(E, ReturnValueSlot(DestPtr, VolatileDest)); - return; - } - - RValue RV = CGF.EmitCallExpr(E); - EmitFinalDestCopy(E, RV); + RValue RV = CGF.EmitCallExpr(E, getReturnValueSlot()); + EmitGCMove(E, RV); } void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) { - RValue RV = CGF.EmitObjCMessageExpr(E); - EmitFinalDestCopy(E, RV); + RValue RV = CGF.EmitObjCMessageExpr(E, getReturnValueSlot()); + EmitGCMove(E, RV); } void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { - RValue RV = CGF.EmitObjCPropertyGet(E); - EmitFinalDestCopy(E, RV); + RValue RV = CGF.EmitObjCPropertyGet(E, getReturnValueSlot()); + EmitGCMove(E, RV); } void AggExprEmitter::VisitObjCImplicitSetterGetterRefExpr( ObjCImplicitSetterGetterRefExpr *E) { - RValue RV = CGF.EmitObjCPropertyGet(E); - EmitFinalDestCopy(E, RV); + RValue RV = CGF.EmitObjCPropertyGet(E, getReturnValueSlot()); + EmitGCMove(E, RV); } void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { @@ -412,11 +474,9 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { RValue::getAggregate(AggLoc, VolatileDest)); } else { bool RequiresGCollection = false; - if (CGF.getContext().getLangOptions().NeXTRuntime) { - QualType LHSTy = E->getLHS()->getType(); - if (const RecordType *FDTTy = LHSTy.getTypePtr()->getAs<RecordType>()) - RequiresGCollection = FDTTy->getDecl()->hasObjectMember(); - } + if (CGF.getContext().getLangOptions().getGCMode()) + RequiresGCollection = TypeRequiresGCollection(E->getLHS()->getType()); + // Codegen the RHS so that it stores directly into the LHS. CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified(), false, false, RequiresGCollection); @@ -559,14 +619,10 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) { llvm::Value *Null = llvm::Constant::getNullValue(CGF.ConvertType(T)); CGF.EmitStoreThroughLValue(RValue::get(Null), LV, T); } else { - // Otherwise, just memset the whole thing to zero. This is legal - // because in LLVM, all default initializers are guaranteed to have a - // bit pattern of all zeros. - // FIXME: That isn't true for member pointers! // There's a potential optimization opportunity in combining // memsets; that would be easy for arrays, but relatively // difficult for structures with the current code. - CGF.EmitMemSetToZero(LV.getAddress(), T); + CGF.EmitNullInitialization(LV.getAddress(), T); } } @@ -738,21 +794,20 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) { return LValue::MakeAddr(Temp, Q); } -void CodeGenFunction::EmitAggregateClear(llvm::Value *DestPtr, QualType Ty) { - assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); - - EmitMemSetToZero(DestPtr, Ty); -} - void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr, QualType Ty, bool isVolatile) { assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); - // Ignore empty classes in C++. if (getContext().getLangOptions().CPlusPlus) { if (const RecordType *RT = Ty->getAs<RecordType>()) { - if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty()) + CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl()); + assert((Record->hasTrivialCopyConstructor() || + Record->hasTrivialCopyAssignment()) && + "Trying to aggregate-copy a type without a trivial copy " + "constructor or assignment operator"); + // Ignore empty classes in C++. + if (Record->isEmpty()) return; } } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index b57cdc93340e..f93c79c74267 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGObjCRuntime.h" using namespace clang; using namespace CodeGen; @@ -255,16 +256,29 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, ReturnValueSlot ReturnValue) { assert(MD->isInstance() && "Trying to emit a member call expr on a static method!"); - if (MD->isCopyAssignment()) { const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext()); if (ClassDecl->hasTrivialCopyAssignment()) { assert(!ClassDecl->hasUserDeclaredCopyAssignment() && "EmitCXXOperatorMemberCallExpr - user declared copy assignment"); - llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + LValue LV = EmitLValue(E->getArg(0)); + llvm::Value *This; + if (LV.isPropertyRef()) { + llvm::Value *AggLoc = CreateMemTemp(E->getArg(1)->getType()); + EmitAggExpr(E->getArg(1), AggLoc, false /*VolatileDest*/); + EmitObjCPropertySet(LV.getPropertyRefExpr(), + RValue::getAggregate(AggLoc, false /*VolatileDest*/)); + return RValue::getAggregate(0, false); + } + else + This = LV.getAddress(); + llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); QualType Ty = E->getType(); - EmitAggregateCopy(This, Src, Ty); + if (ClassDecl->hasObjectMember()) + CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, This, Src, Ty); + else + EmitAggregateCopy(This, Src, Ty); return RValue::get(This); } } @@ -273,8 +287,15 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), FPT->isVariadic()); - - llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + LValue LV = EmitLValue(E->getArg(0)); + llvm::Value *This; + if (LV.isPropertyRef()) { + RValue RV = EmitLoadOfPropertyRefLValue(LV, E->getArg(0)->getType()); + assert (!RV.isScalar() && "EmitCXXOperatorMemberCallExpr"); + This = RV.getAggregateAddr(); + } + else + This = LV.getAddress(); llvm::Value *Callee; if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0))) @@ -305,11 +326,13 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, return; } // Code gen optimization to eliminate copy constructor and return - // its first argument instead. + // its first argument instead, if in fact that argument is a temporary + // object. if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { - const Expr *Arg = E->getArg(0)->getTemporaryObject(); - EmitAggExpr(Arg, Dest, false); - return; + if (const Expr *Arg = E->getArg(0)->getTemporaryObject()) { + EmitAggExpr(Arg, Dest, false); + return; + } } if (Array) { QualType BaseElementTy = getContext().getBaseElementType(Array); @@ -851,6 +874,8 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, ToVoid = true; } else { LTy = LTy->getPointerTo(); + + // FIXME: What if exceptions are disabled? ThrowOnBad = true; } @@ -917,15 +942,21 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, if (ThrowOnBad) { BadCastBlock = createBasicBlock(); - Builder.CreateCondBr(Builder.CreateIsNotNull(V), ContBlock, BadCastBlock); EmitBlock(BadCastBlock); - /// Call __cxa_bad_cast + /// Invoke __cxa_bad_cast ResultType = llvm::Type::getVoidTy(VMContext); const llvm::FunctionType *FBadTy; FBadTy = llvm::FunctionType::get(ResultType, false); llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast"); - Builder.CreateCall(F)->setDoesNotReturn(); + if (llvm::BasicBlock *InvokeDest = getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + Builder.CreateInvoke(F, Cont, InvokeDest)->setDoesNotReturn(); + EmitBlock(Cont); + } else { + // FIXME: Does this ever make sense? + Builder.CreateCall(F)->setDoesNotReturn(); + } Builder.CreateUnreachable(); } } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 2595ff0060ca..551a47aa9f80 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -984,32 +984,81 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, return C; } -static bool containsPointerToDataMember(CodeGenTypes &Types, QualType T) { - // No need to check for member pointers when not compiling C++. - if (!Types.getContext().getLangOptions().CPlusPlus) - return false; - - T = Types.getContext().getBaseElementType(T); - - if (const RecordType *RT = T->getAs<RecordType>()) { - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - - // FIXME: It would be better if there was a way to explicitly compute the - // record layout instead of converting to a type. - Types.ConvertTagDeclType(RD); +static void +FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, + std::vector<llvm::Constant *> &Elements, + uint64_t StartOffset) { + assert(StartOffset % 8 == 0 && "StartOffset not byte aligned!"); + + if (!CGM.getTypes().ContainsPointerToDataMember(T)) + return; + + if (const ConstantArrayType *CAT = + CGM.getContext().getAsConstantArrayType(T)) { + QualType ElementTy = CAT->getElementType(); + uint64_t ElementSize = CGM.getContext().getTypeSize(ElementTy); - const CGRecordLayout &Layout = Types.getCGRecordLayout(RD); - return Layout.containsPointerToDataMember(); - } + for (uint64_t I = 0, E = CAT->getSize().getZExtValue(); I != E; ++I) { + FillInNullDataMemberPointers(CGM, ElementTy, Elements, + StartOffset + I * ElementSize); + } + } else if (const RecordType *RT = T->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + // Go through all bases and fill in any null pointer to data members. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->isVirtual() && "Should not see virtual bases here!"); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Ignore empty bases. + if (BaseDecl->isEmpty()) + continue; + + // Ignore bases that don't have any pointer to data members. + if (!CGM.getTypes().ContainsPointerToDataMember(BaseDecl)) + continue; + + uint64_t BaseOffset = Layout.getBaseClassOffset(BaseDecl); + FillInNullDataMemberPointers(CGM, I->getType(), + Elements, StartOffset + BaseOffset); + } - if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) - return !MPT->getPointeeType()->isFunctionType(); + // Visit all fields. + unsigned FieldNo = 0; + for (RecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I, ++FieldNo) { + QualType FieldType = I->getType(); + + if (!CGM.getTypes().ContainsPointerToDataMember(FieldType)) + continue; + + uint64_t FieldOffset = StartOffset + Layout.getFieldOffset(FieldNo); + FillInNullDataMemberPointers(CGM, FieldType, Elements, FieldOffset); + } + } else { + assert(T->isMemberPointerType() && "Should only see member pointers here!"); + assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() && + "Should only see pointers to data members here!"); - return false; + uint64_t StartIndex = StartOffset / 8; + uint64_t EndIndex = StartIndex + CGM.getContext().getTypeSize(T) / 8; + + llvm::Constant *NegativeOne = + llvm::ConstantInt::get(llvm::Type::getInt8Ty(CGM.getLLVMContext()), + -1ULL, /*isSigned=*/true); + + // Fill in the null data member pointer. + for (uint64_t I = StartIndex; I != EndIndex; ++I) + Elements[I] = NegativeOne; + } } llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { - if (!containsPointerToDataMember(getTypes(), T)) + if (!getTypes().ContainsPointerToDataMember(T)) return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T)); if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) { @@ -1029,21 +1078,60 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { if (const RecordType *RT = T->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - assert(!RD->getNumBases() && - "FIXME: Handle zero-initializing structs with bases and " - "pointers to data members."); const llvm::StructType *STy = cast<llvm::StructType>(getTypes().ConvertTypeForMem(T)); unsigned NumElements = STy->getNumElements(); std::vector<llvm::Constant *> Elements(NumElements); + const CGRecordLayout &Layout = getTypes().getCGRecordLayout(RD); + + // Go through all bases and fill in any null pointer to data members. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->isVirtual() && "Should not see virtual bases here!"); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Ignore empty bases. + if (BaseDecl->isEmpty()) + continue; + + // Ignore bases that don't have any pointer to data members. + if (!getTypes().ContainsPointerToDataMember(BaseDecl)) + continue; + + // Currently, all bases are arrays of i8. Figure out how many elements + // this base array has. + unsigned BaseFieldNo = Layout.getNonVirtualBaseLLVMFieldNo(BaseDecl); + const llvm::ArrayType *BaseArrayTy = + cast<llvm::ArrayType>(STy->getElementType(BaseFieldNo)); + + unsigned NumBaseElements = BaseArrayTy->getNumElements(); + std::vector<llvm::Constant *> BaseElements(NumBaseElements); + + // Now fill in null data member pointers. + FillInNullDataMemberPointers(*this, I->getType(), BaseElements, 0); + + // Now go through all other elements and zero them out. + if (NumBaseElements) { + llvm::Constant *Zero = + llvm::ConstantInt::get(llvm::Type::getInt8Ty(getLLVMContext()), 0); + + for (unsigned I = 0; I != NumBaseElements; ++I) { + if (!BaseElements[I]) + BaseElements[I] = Zero; + } + } + + Elements[BaseFieldNo] = llvm::ConstantArray::get(BaseArrayTy, + BaseElements); + } + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) { const FieldDecl *FD = *I; - - const CGRecordLayout &RL = - getTypes().getCGRecordLayout(FD->getParent()); - unsigned FieldNo = RL.getLLVMFieldNo(FD); + unsigned FieldNo = Layout.getLLVMFieldNo(FD); Elements[FieldNo] = EmitNullConstant(FD->getType()); } @@ -1056,6 +1144,7 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { return llvm::ConstantStruct::get(STy, Elements); } + assert(T->isMemberPointerType() && "Should only see member pointers here!"); assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() && "Should only see pointers to data members here!"); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 984968802382..2108414c5ae6 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -96,6 +96,9 @@ public: Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, QualType SrcTy, QualType DstTy); + /// EmitNullValue - Emit a value that corresponds to null for the given type. + Value *EmitNullValue(QualType Ty); + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// @@ -123,10 +126,10 @@ public: return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); } Value *VisitCXXZeroInitValueExpr(const CXXZeroInitValueExpr *E) { - return llvm::Constant::getNullValue(ConvertType(E->getType())); + return EmitNullValue(E->getType()); } Value *VisitGNUNullExpr(const GNUNullExpr *E) { - return llvm::Constant::getNullValue(ConvertType(E->getType())); + return EmitNullValue(E->getType()); } Value *VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) { return llvm::ConstantInt::get(ConvertType(E->getType()), @@ -186,7 +189,7 @@ public: Value *VisitInitListExpr(InitListExpr *E); Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { - return llvm::Constant::getNullValue(ConvertType(E->getType())); + return CGF.CGM.EmitNullConstant(E->getType()); } Value *VisitCastExpr(CastExpr *E) { // Make sure to evaluate VLA bounds now so that we have them for later. @@ -278,7 +281,7 @@ public: } Value *VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) { - return llvm::Constant::getNullValue(ConvertType(E->getType())); + return EmitNullValue(E->getType()); } Value *VisitCXXThrowExpr(const CXXThrowExpr *E) { @@ -549,6 +552,19 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, return EmitScalarConversion(Src.first, SrcTy, DstTy); } +Value *ScalarExprEmitter::EmitNullValue(QualType Ty) { + const llvm::Type *LTy = ConvertType(Ty); + + if (!Ty->isMemberPointerType()) + return llvm::Constant::getNullValue(LTy); + + assert(!Ty->isMemberFunctionPointerType() && + "member function pointers are not scalar!"); + + // Itanium C++ ABI 2.3: + // A NULL pointer is represented as -1. + return llvm::ConstantInt::get(LTy, -1ULL, /*isSigned=*/true); +} //===----------------------------------------------------------------------===// // Visitor Methods @@ -1334,7 +1350,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { } const QualType ElementType = PT ? PT->getPointeeType() : OPT->getPointeeType(); // Handle interface types, which are not represented with a concrete type. - if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) { + if (const ObjCObjectType *OIT = ElementType->getAs<ObjCObjectType>()) { llvm::Value *InterfaceSize = llvm::ConstantInt::get(Idx->getType(), CGF.getContext().getTypeSizeInChars(OIT).getQuantity()); @@ -1402,8 +1418,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { Idx = Builder.CreateNeg(Idx, "sub.ptr.neg"); // Handle interface types, which are not represented with a concrete type. - if (const ObjCInterfaceType *OIT = - dyn_cast<ObjCInterfaceType>(LHSElementType)) { + if (const ObjCObjectType *OIT = LHSElementType->getAs<ObjCObjectType>()) { llvm::Value *InterfaceSize = llvm::ConstantInt::get(Idx->getType(), CGF.getContext(). diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 8426f7105be4..7c842a94986c 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -47,7 +47,8 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) { } -RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { +RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, + ReturnValueSlot Return) { // Only the lookup mechanism and first two arguments of the method // implementation vary between runtimes. We can get the receiver and // arguments in generic code. @@ -64,10 +65,11 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { break; case ObjCMessageExpr::Class: { - const ObjCInterfaceType *IFace - = E->getClassReceiver()->getAs<ObjCInterfaceType>(); - OID = IFace->getDecl(); - assert(IFace && "Invalid Objective-C class message send"); + const ObjCObjectType *ObjTy + = E->getClassReceiver()->getAs<ObjCObjectType>(); + assert(ObjTy && "Invalid Objective-C class message send"); + OID = ObjTy->getInterface(); + assert(OID && "Invalid Objective-C class message send"); Receiver = Runtime.GetClass(Builder, OID); isClassMessage = true; break; @@ -92,7 +94,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { // super is only valid in an Objective-C method const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext()); - return Runtime.GenerateMessageSendSuper(*this, E->getType(), + return Runtime.GenerateMessageSendSuper(*this, Return, E->getType(), E->getSelector(), OMD->getClassInterface(), isCategoryImpl, @@ -102,7 +104,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { E->getMethodDecl()); } - return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(), + return Runtime.GenerateMessageSend(*this, Return, E->getType(), + E->getSelector(), Receiver, Args, OID, E->getMethodDecl()); } @@ -157,9 +160,6 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); assert(OMD && "Invalid call to generate getter (empty method)"); - // FIXME: This is rather murky, we create this here since they will not have - // been created by Sema for us. - OMD->createImplicitParams(getContext(), IMP->getClassInterface()); StartObjCMethod(OMD, IMP->getClassInterface()); // Determine if we should use an objc_getProperty call for @@ -208,8 +208,9 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, Types.ConvertType(PD->getType()))); EmitReturnOfRValue(RV, PD->getType()); } else { - LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); if (Ivar->getType()->isAnyComplexType()) { + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), + Ivar, 0); ComplexPairTy Pair = LoadComplexFromAddr(LV.getAddress(), LV.isVolatileQualified()); StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified()); @@ -219,6 +220,8 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(Ivar->getType()))) && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect && CGM.getObjCRuntime().GetCopyStructFunction()) { + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), + Ivar, 0); llvm::Value *GetCopyStructFn = CGM.getObjCRuntime().GetCopyStructFunction(); CodeGenTypes &Types = CGM.getTypes(); @@ -251,9 +254,23 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, FunctionType::ExtInfo()), GetCopyStructFn, ReturnValueSlot(), Args); } - else - EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); + else { + if (PID->getGetterCXXConstructor()) { + ReturnStmt *Stmt = + new (getContext()) ReturnStmt(SourceLocation(), + PID->getGetterCXXConstructor(), + 0); + EmitReturnStmt(*Stmt); + } + else { + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), + Ivar, 0); + EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); + } + } } else { + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), + Ivar, 0); CodeGenTypes &Types = CGM.getTypes(); RValue RV = EmitLoadOfLValue(LV, Ivar->getType()); RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(), @@ -274,9 +291,6 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyDecl *PD = PID->getPropertyDecl(); ObjCMethodDecl *OMD = PD->getSetterMethodDecl(); assert(OMD && "Invalid call to generate setter (empty method)"); - // FIXME: This is rather murky, we create this here since they will not have - // been created by Sema for us. - OMD->createImplicitParams(getContext(), IMP->getClassInterface()); StartObjCMethod(OMD, IMP->getClassInterface()); bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy; @@ -368,6 +382,10 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, FunctionType::ExtInfo()), GetCopyStructFn, ReturnValueSlot(), Args); + } else if (PID->getSetterCXXAssignment()) { + EmitAnyExpr(PID->getSetterCXXAssignment(), (llvm::Value *)0, false, true, + false); + } else { // FIXME: Find a clean way to avoid AST node creation. SourceLocation Loc = PD->getLocation(); @@ -425,8 +443,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, llvm::Value *SelfAsId = Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy)); EmitReturnOfRValue(RValue::get(SelfAsId), IdTy); - } - else { + } else { // dtor for (size_t i = IvarInitializers.size(); i > 0; --i) { FieldDecl *Field = IvarInitializers[i - 1]->getMember(); @@ -442,7 +459,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, const RecordType *RT = FieldType->getAs<RecordType>(); CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(getContext()); - if (!Dtor->isTrivial()) + if (!Dtor->isTrivial()) { if (Array) { const llvm::Type *BasePtr = ConvertType(FieldType); BasePtr = llvm::PointerType::getUnqual(BasePtr); @@ -450,12 +467,13 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, Builder.CreateBitCast(LV.getAddress(), BasePtr); EmitCXXAggrDestructorCall(Dtor, Array, BaseAddrPtr); - } - else + } else { EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, LV.getAddress()); - } + } + } + } } FinishFunction(); } @@ -478,8 +496,6 @@ bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) { llvm::Value *CodeGenFunction::LoadObjCSelf() { const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); - // See if we need to lazily forward self inside a block literal. - BlockForwardSelf(); return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self"); } @@ -492,12 +508,14 @@ QualType CodeGenFunction::TypeOfSelfObject() { } RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp, - const Selector &S) { + const Selector &S, + ReturnValueSlot Return) { llvm::Value *Receiver = LoadObjCSelf(); const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); bool isClassMessage = OMD->isClassMethod(); bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext()); return CGM.getObjCRuntime().GenerateMessageSendSuper(*this, + Return, Exp->getType(), S, OMD->getClassInterface(), @@ -508,15 +526,16 @@ RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp, } -RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) { +RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp, + ReturnValueSlot Return) { Exp = Exp->IgnoreParens(); // FIXME: Split it into two separate routines. if (const ObjCPropertyRefExpr *E = dyn_cast<ObjCPropertyRefExpr>(Exp)) { Selector S = E->getProperty()->getGetterName(); if (isa<ObjCSuperExpr>(E->getBase())) - return EmitObjCSuperPropertyGet(E, S); + return EmitObjCSuperPropertyGet(E, S, Return); return CGM.getObjCRuntime(). - GenerateMessageSend(*this, Exp->getType(), S, + GenerateMessageSend(*this, Return, Exp->getType(), S, EmitScalarExpr(E->getBase()), CallArgList()); } else { @@ -528,11 +547,11 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) { const ObjCInterfaceDecl *OID = KE->getInterfaceDecl(); Receiver = CGM.getObjCRuntime().GetClass(Builder, OID); } else if (isa<ObjCSuperExpr>(KE->getBase())) - return EmitObjCSuperPropertyGet(KE, S); + return EmitObjCSuperPropertyGet(KE, S, Return); else Receiver = EmitScalarExpr(KE->getBase()); return CGM.getObjCRuntime(). - GenerateMessageSend(*this, Exp->getType(), S, + GenerateMessageSend(*this, Return, Exp->getType(), S, Receiver, CallArgList(), KE->getInterfaceDecl()); } @@ -548,6 +567,7 @@ void CodeGenFunction::EmitObjCSuperPropertySet(const Expr *Exp, bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext()); Args.push_back(std::make_pair(Src, Exp->getType())); CGM.getObjCRuntime().GenerateMessageSendSuper(*this, + ReturnValueSlot(), Exp->getType(), S, OMD->getClassInterface(), @@ -569,7 +589,8 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp, } CallArgList Args; Args.push_back(std::make_pair(Src, E->getType())); - CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, + CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), + getContext().VoidTy, S, EmitScalarExpr(E->getBase()), Args); } else if (const ObjCImplicitSetterGetterRefExpr *E = @@ -586,7 +607,8 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp, } else Receiver = EmitScalarExpr(E->getBase()); Args.push_back(std::make_pair(Src, E->getType())); - CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, + CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), + getContext().VoidTy, S, Receiver, Args, E->getInterfaceDecl()); } else @@ -618,7 +640,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ // Fast enumeration state. QualType StateTy = getContext().getObjCFastEnumerationStateType(); llvm::Value *StatePtr = CreateMemTemp(StateTy, "state.ptr"); - EmitMemSetToZero(StatePtr, StateTy); + EmitNullInitialization(StatePtr, StateTy); // Number of elements in the items array. static const unsigned NumItems = 16; @@ -653,7 +675,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ getContext().UnsignedLongTy)); RValue CountRV = - CGM.getObjCRuntime().GenerateMessageSend(*this, + CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), getContext().UnsignedLongTy, FastEnumSel, Collection, Args); @@ -778,7 +800,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitBlock(FetchMore); CountRV = - CGM.getObjCRuntime().GenerateMessageSend(*this, + CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), getContext().UnsignedLongTy, FastEnumSel, Collection, Args); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 3c51b7ee9de7..6c25afeb9ad3 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -142,6 +142,7 @@ public: virtual llvm::Constant *GenerateConstantString(const StringLiteral *); virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, @@ -150,6 +151,7 @@ public: const ObjCMethodDecl *Method); virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, @@ -235,6 +237,21 @@ static std::string SymbolNameForMethod(const std::string &ClassName, const return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" + CategoryName + "_" + MethodNameColonStripped; } +static std::string MangleSelectorTypes(const std::string &TypeString) { + std::string Mangled = TypeString; + // Simple mangling to avoid breaking when we mix JIT / static code. + // Not part of the ABI, subject to change without notice. + std::replace(Mangled.begin(), Mangled.end(), '@', '_'); + std::replace(Mangled.begin(), Mangled.end(), ':', 'J'); + std::replace(Mangled.begin(), Mangled.end(), '*', 'e'); + std::replace(Mangled.begin(), Mangled.end(), '#', 'E'); + std::replace(Mangled.begin(), Mangled.end(), ':', 'j'); + std::replace(Mangled.begin(), Mangled.end(), '(', 'g'); + std::replace(Mangled.begin(), Mangled.end(), ')', 'G'); + std::replace(Mangled.begin(), Mangled.end(), '[', 'h'); + std::replace(Mangled.begin(), Mangled.end(), ']', 'H'); + return Mangled; +} CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) : CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0), @@ -440,6 +457,7 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { ///should be called. CodeGen::RValue CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, @@ -567,7 +585,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3); llvm::Instruction *call; - RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs, + RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs, 0, &call); call->setMetadata(msgSendMDKind, node); return msgRet; @@ -576,6 +594,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, /// Generate code for a message send expression. CodeGen::RValue CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, @@ -611,16 +630,16 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *startBB = 0; llvm::BasicBlock *messageBB = 0; - llvm::BasicBlock *contiueBB = 0; + llvm::BasicBlock *continueBB = 0; if (!isPointerSizedReturn) { startBB = Builder.GetInsertBlock(); messageBB = CGF.createBasicBlock("msgSend"); - contiueBB = CGF.createBasicBlock("continue"); + continueBB = CGF.createBasicBlock("continue"); llvm::Value *isNil = Builder.CreateICmpEQ(Receiver, llvm::Constant::getNullValue(Receiver->getType())); - Builder.CreateCondBr(isNil, contiueBB, messageBB); + Builder.CreateCondBr(isNil, continueBB, messageBB); CGF.EmitBlock(messageBB); } @@ -711,12 +730,15 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, cast<llvm::CallInst>(imp)->setMetadata(msgSendMDKind, node); } llvm::Instruction *call; - RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs, + RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs, 0, &call); call->setMetadata(msgSendMDKind, node); + if (!isPointerSizedReturn) { - CGF.EmitBlock(contiueBB); + messageBB = CGF.Builder.GetInsertBlock(); + CGF.Builder.CreateBr(continueBB); + CGF.EmitBlock(continueBB); if (msgRet.isScalar()) { llvm::Value *v = msgRet.getScalarVal(); llvm::PHINode *phi = Builder.CreatePHI(v->getType()); @@ -1665,34 +1687,36 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { llvm::Constant *Idxs[] = {Zeros[0], llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]}; llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy, - true, llvm::GlobalValue::InternalLinkage, - llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), - ".objc_sel_ptr"); + true, llvm::GlobalValue::LinkOnceODRLinkage, + llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), + MangleSelectorTypes(".objc_sel_ptr"+iter->first.first+"."+ + iter->first.second)); // If selectors are defined as an opaque type, cast the pointer to this // type. if (isSelOpaque) { SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, llvm::PointerType::getUnqual(SelectorTy)); } - (*iter).second->setAliasee(SelPtr); + (*iter).second->replaceAllUsesWith(SelPtr); + (*iter).second->eraseFromParent(); } for (llvm::StringMap<llvm::GlobalAlias*>::iterator iter=UntypedSelectors.begin(), iterEnd = UntypedSelectors.end(); iter != iterEnd; iter++) { llvm::Constant *Idxs[] = {Zeros[0], llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]}; - llvm::Constant *SelPtr = new llvm::GlobalVariable - (TheModule, SelStructPtrTy, - true, llvm::GlobalValue::InternalLinkage, - llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), - ".objc_sel_ptr"); + llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy, + true, llvm::GlobalValue::LinkOnceODRLinkage, + llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), + MangleSelectorTypes(std::string(".objc_sel_ptr")+iter->getKey().str())); // If selectors are defined as an opaque type, cast the pointer to this // type. if (isSelOpaque) { SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, llvm::PointerType::getUnqual(SelectorTy)); } - (*iter).second->setAliasee(SelPtr); + (*iter).second->replaceAllUsesWith(SelPtr); + (*iter).second->eraseFromParent(); } // Number of classes defined. Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext), @@ -1922,11 +1946,11 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const ObjCObjectPointerType *OPT = CatchDecl->getType()->getAs<ObjCObjectPointerType>(); assert(OPT && "Invalid @catch type."); - const ObjCInterfaceType *IT = - OPT->getPointeeType()->getAs<ObjCInterfaceType>(); - assert(IT && "Invalid @catch type."); + const ObjCInterfaceDecl *IDecl = + OPT->getObjectType()->getInterface(); + assert(IDecl && "Invalid @catch type."); llvm::Value *EHType = - MakeConstantString(IT->getDecl()->getNameAsString()); + MakeConstantString(IDecl->getNameAsString()); ESelArgs.push_back(EHType); } } @@ -2208,7 +2232,8 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { - const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->getDecl(); + const ObjCInterfaceDecl *ID = + ObjectTy->getAs<ObjCObjectType>()->getInterface(); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, EmitIvarOffset(CGF, ID, Ivar)); } diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 77eabbfd4141..d3bafd7eda78 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -973,6 +973,7 @@ protected: bool AddToUsed); CodeGen::RValue EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, llvm::Value *Sel, llvm::Value *Arg0, @@ -1039,6 +1040,7 @@ private: llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID); CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Arg0, @@ -1126,6 +1128,7 @@ public: virtual llvm::Function *ModuleInitFunction(); virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, @@ -1135,6 +1138,7 @@ public: virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, @@ -1279,6 +1283,7 @@ private: ObjCProtocolDecl::protocol_iterator end); CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, @@ -1354,6 +1359,7 @@ public: virtual llvm::Function *ModuleInitFunction(); virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, @@ -1363,6 +1369,7 @@ public: virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, @@ -1515,6 +1522,7 @@ llvm::Constant *CGObjCCommonMac::GenerateConstantString( /// which class's method should be called. CodeGen::RValue CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, @@ -1566,7 +1574,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, Target = CGF.Builder.CreateBitCast(Target, ClassTy); CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - return EmitLegacyMessageSend(CGF, ResultType, + return EmitLegacyMessageSend(CGF, Return, ResultType, EmitSelector(CGF.Builder, Sel), ObjCSuper, ObjCTypes.SuperPtrCTy, true, CallArgs, Method, ObjCTypes); @@ -1574,13 +1582,14 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, /// Generate code for a message send expression. CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { - return EmitLegacyMessageSend(CGF, ResultType, + return EmitLegacyMessageSend(CGF, Return, ResultType, EmitSelector(CGF.Builder, Sel), Receiver, CGF.getContext().getObjCIdType(), false, CallArgs, Method, ObjCTypes); @@ -1588,6 +1597,7 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, CodeGen::RValue CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, llvm::Value *Sel, llvm::Value *Arg0, @@ -1634,7 +1644,7 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, assert(Fn && "EmitLegacyMessageSend - unknown API"); Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy)); - return CGF.EmitCall(FnInfo, Fn, ReturnValueSlot(), ActualArgs); + return CGF.EmitCall(FnInfo, Fn, Return, ActualArgs); } llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder, @@ -2701,12 +2711,12 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, } assert(OPT && "Unexpected non-object pointer type in @catch"); - QualType T = OPT->getPointeeType(); - const ObjCInterfaceType *ObjCType = T->getAs<ObjCInterfaceType>(); - assert(ObjCType && "Catch parameter must have Objective-C type!"); + const ObjCObjectType *ObjTy = OPT->getObjectType(); + ObjCInterfaceDecl *IDecl = ObjTy->getInterface(); + assert(IDecl && "Catch parameter must have Objective-C type!"); // Check if the @catch block matches the exception object. - llvm::Value *Class = EmitClassRef(CGF.Builder, ObjCType->getDecl()); + llvm::Value *Class = EmitClassRef(CGF.Builder, IDecl); llvm::Value *Match = CGF.Builder.CreateCall2(ObjCTypes.getExceptionMatchFn(), @@ -2938,7 +2948,8 @@ LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { - const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->getDecl(); + const ObjCInterfaceDecl *ID = + ObjectTy->getAs<ObjCObjectType>()->getInterface(); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, EmitIvarOffset(CGF, ID, Ivar)); } @@ -3669,7 +3680,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) // id self; // Class cls; // } - RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, + RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct, Ctx.getTranslationUnitDecl(), SourceLocation(), &Ctx.Idents.get("_objc_super")); @@ -4131,7 +4142,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // }; // First the clang type for struct _message_ref_t - RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, + RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct, Ctx.getTranslationUnitDecl(), SourceLocation(), &Ctx.Idents.get("_message_ref_t")); @@ -5095,12 +5106,12 @@ CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { /// @encode /// LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar( - CodeGen::CodeGenFunction &CGF, - QualType ObjectTy, - llvm::Value *BaseValue, - const ObjCIvarDecl *Ivar, - unsigned CVRQualifiers) { - const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->getDecl(); + CodeGen::CodeGenFunction &CGF, + QualType ObjectTy, + llvm::Value *BaseValue, + const ObjCIvarDecl *Ivar, + unsigned CVRQualifiers) { + ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCObjectType>()->getInterface(); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, EmitIvarOffset(CGF, ID, Ivar)); } @@ -5114,6 +5125,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset( CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, @@ -5213,12 +5225,13 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true); Callee = CGF.Builder.CreateBitCast(Callee, llvm::PointerType::getUnqual(FTy)); - return CGF.EmitCall(FnInfo1, Callee, ReturnValueSlot(), ActualArgs); + return CGF.EmitCall(FnInfo1, Callee, Return, ActualArgs); } /// Generate code for a message send expression in the nonfragile abi. CodeGen::RValue CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, @@ -5226,10 +5239,11 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { return LegacyDispatchedSelector(Sel) - ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), + ? EmitLegacyMessageSend(CGF, Return, ResultType, + EmitSelector(CGF.Builder, Sel), Receiver, CGF.getContext().getObjCIdType(), false, CallArgs, Method, ObjCTypes) - : EmitMessageSend(CGF, ResultType, Sel, + : EmitMessageSend(CGF, Return, ResultType, Sel, Receiver, CGF.getContext().getObjCIdType(), false, CallArgs); } @@ -5336,6 +5350,7 @@ llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder, /// which class's method should be called. CodeGen::RValue CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, @@ -5378,10 +5393,11 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); return (LegacyDispatchedSelector(Sel)) - ? EmitLegacyMessageSend(CGF, ResultType,EmitSelector(CGF.Builder, Sel), + ? EmitLegacyMessageSend(CGF, Return, ResultType, + EmitSelector(CGF.Builder, Sel), ObjCSuper, ObjCTypes.SuperPtrCTy, true, CallArgs, Method, ObjCTypes) - : EmitMessageSend(CGF, ResultType, Sel, + : EmitMessageSend(CGF, Return, ResultType, Sel, ObjCSuper, ObjCTypes.SuperPtrCTy, true, CallArgs); } diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index 654ad0a4bfae..8de7f10b8612 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -119,6 +119,7 @@ public: /// a property setter or getter. virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot ReturnSlot, QualType ResultType, Selector Sel, llvm::Value *Receiver, @@ -134,6 +135,7 @@ public: /// a property setter or getter. virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot ReturnSlot, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index 9f966fb7ae46..e95591e5cc01 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -168,6 +168,10 @@ private: /// field no. This info is populated by record builder. llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields; + // FIXME: Maybe we could use a CXXBaseSpecifier as the key and use a single + // map for both virtual and non virtual bases. + llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBaseFields; + /// Whether one of the fields in this record layout is a pointer to data /// member, or a struct that contains pointer to data member. bool ContainsPointerToDataMember : 1; @@ -194,6 +198,11 @@ public: return FieldInfo.lookup(FD); } + unsigned getNonVirtualBaseLLVMFieldNo(const CXXRecordDecl *RD) const { + assert(NonVirtualBaseFields.count(RD) && "Invalid non-virtual base!"); + return NonVirtualBaseFields.lookup(RD); + } + /// \brief Return the BitFieldInfo that corresponds to the field FD. const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const { assert(FD->isBitField() && "Invalid call for non bit-field decl!"); diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 6302cf8d1fc0..9f1687577c3e 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -42,6 +42,9 @@ public: typedef std::pair<const FieldDecl *, CGBitFieldInfo> LLVMBitFieldInfo; llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields; + typedef std::pair<const CXXRecordDecl *, unsigned> LLVMBaseInfo; + llvm::SmallVector<LLVMBaseInfo, 16> LLVMNonVirtualBases; + /// ContainsPointerToDataMember - Whether one of the fields in this record /// layout is a pointer to data member, or a struct that contains pointer to /// data member. @@ -81,8 +84,13 @@ private: /// Returns false if the operation failed because the struct is not packed. bool LayoutFields(const RecordDecl *D); - /// LayoutBases - layout the bases and vtable pointer of a record decl. - void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout); + /// LayoutNonVirtualBase - layout a single non-virtual base. + void LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl, + uint64_t BaseOffset); + + /// LayoutNonVirtualBases - layout the non-virtual bases of a record decl. + void LayoutNonVirtualBases(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout); /// LayoutField - layout a single field. Returns false if the operation failed /// because the current struct is not packed. @@ -110,6 +118,7 @@ private: /// CheckForPointerToDataMember - Check if the given type contains a pointer /// to data member. void CheckForPointerToDataMember(QualType T); + void CheckForPointerToDataMember(const CXXRecordDecl *RD); public: CGRecordLayoutBuilder(CodeGenTypes &Types) @@ -143,6 +152,7 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { FieldTypes.clear(); LLVMFields.clear(); LLVMBitFields.clear(); + LLVMNonVirtualBases.clear(); LayoutFields(D); } @@ -319,8 +329,9 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, if (const RecordType *RT = D->getType()->getAs<RecordType>()) { const RecordDecl *RD = cast<RecordDecl>(RT->getDecl()); - if (const PragmaPackAttr *PPA = RD->getAttr<PragmaPackAttr>()) { - if (PPA->getAlignment() != TypeAlignment * 8 && !Packed) + if (const MaxFieldAlignmentAttr *MFAA = + RD->getAttr<MaxFieldAlignmentAttr>()) { + if (MFAA->getAlignment() != TypeAlignment * 8 && !Packed) return false; } } @@ -435,16 +446,66 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { AppendPadding(Layout.getSize() / 8, Align); } -void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD, - const ASTRecordLayout &Layout) { +void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl, + uint64_t BaseOffset) { + const ASTRecordLayout &Layout = + Types.getContext().getASTRecordLayout(BaseDecl); + + uint64_t NonVirtualSize = Layout.getNonVirtualSize(); + + if (BaseDecl->isEmpty()) { + // FIXME: Lay out empty bases. + return; + } + + CheckForPointerToDataMember(BaseDecl); + + // FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can. + AppendPadding(BaseOffset / 8, 1); + + // Append the base field. + LLVMNonVirtualBases.push_back(LLVMBaseInfo(BaseDecl, FieldTypes.size())); + + AppendBytes(NonVirtualSize / 8); +} + +void +CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout) { + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + // Check if we need to add a vtable pointer. - if (RD->isDynamicClass() && !Layout.getPrimaryBase()) { - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8PtrTy(Types.getLLVMContext()); + if (RD->isDynamicClass()) { + if (!PrimaryBase) { + const llvm::Type *FunctionType = + llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()), + /*isVarArg=*/true); + const llvm::Type *VTableTy = FunctionType->getPointerTo(); + + assert(NextFieldOffsetInBytes == 0 && + "VTable pointer must come first!"); + AppendField(NextFieldOffsetInBytes, VTableTy->getPointerTo()); + } else { + // FIXME: Handle a virtual primary base. + if (!Layout.getPrimaryBaseWasVirtual()) + LayoutNonVirtualBase(PrimaryBase, 0); + } + } - assert(NextFieldOffsetInBytes == 0 && - "VTable pointer must come first!"); - AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo()); + // Layout the non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // We've already laid out the primary base. + if (BaseDecl == PrimaryBase && !Layout.getPrimaryBaseWasVirtual()) + continue; + + LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl)); } } @@ -455,7 +516,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D); if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) - LayoutBases(RD, Layout); + LayoutNonVirtualBases(RD, Layout); unsigned FieldNo = 0; @@ -561,15 +622,24 @@ void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) { } else if (const RecordType *RT = T->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - // FIXME: It would be better if there was a way to explicitly compute the - // record layout instead of converting to a type. - Types.ConvertTagDeclType(RD); + return CheckForPointerToDataMember(RD); + } +} - const CGRecordLayout &Layout = Types.getCGRecordLayout(RD); +void +CGRecordLayoutBuilder::CheckForPointerToDataMember(const CXXRecordDecl *RD) { + // This record already contains a member pointer. + if (ContainsPointerToDataMember) + return; - if (Layout.containsPointerToDataMember()) - ContainsPointerToDataMember = true; - } + // FIXME: It would be better if there was a way to explicitly compute the + // record layout instead of converting to a type. + Types.ConvertTagDeclType(RD); + + const CGRecordLayout &Layout = Types.getCGRecordLayout(RD); + + if (Layout.containsPointerToDataMember()) + ContainsPointerToDataMember = true; } CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { @@ -584,13 +654,17 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { CGRecordLayout *RL = new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); + // Add all the non-virtual base field numbers. + RL->NonVirtualBaseFields.insert(Builder.LLVMNonVirtualBases.begin(), + Builder.LLVMNonVirtualBases.end()); + // Add all the field numbers. - for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i) - RL->FieldInfo.insert(Builder.LLVMFields[i]); + RL->FieldInfo.insert(Builder.LLVMFields.begin(), + Builder.LLVMFields.end()); // Add bitfield info. - for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) - RL->BitFields.insert(Builder.LLVMBitFields[i]); + RL->BitFields.insert(Builder.LLVMBitFields.begin(), + Builder.LLVMBitFields.end()); // Dump the layout, if requested. if (getContext().getLangOptions().DumpRecordLayouts) { diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index a914c80da2ac..efde3807111f 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -30,7 +30,10 @@ using namespace CodeGen; void CodeGenFunction::EmitStopPoint(const Stmt *S) { if (CGDebugInfo *DI = getDebugInfo()) { - DI->setLocation(S->getLocStart()); + if (isa<DeclStmt>(S)) + DI->setLocation(S->getLocEnd()); + else + DI->setLocation(S->getLocStart()); DI->EmitStopPoint(CurFn, Builder); } } @@ -76,8 +79,11 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { // Expression emitters don't handle unreachable blocks yet, so look for one // explicitly here. This handles the common case of a call to a noreturn // function. + // We can't erase blocks with an associated cleanup size here since the + // memory might be reused, leaving the old cleanup info pointing at a new + // block. if (llvm::BasicBlock *CurBB = Builder.GetInsertBlock()) { - if (CurBB->empty() && CurBB->use_empty()) { + if (CurBB->empty() && CurBB->use_empty() && !BlockScopes.count(CurBB)) { CurBB->eraseFromParent(); Builder.ClearInsertionPoint(); } @@ -484,8 +490,6 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) { } void CodeGenFunction::EmitForStmt(const ForStmt &S) { - // FIXME: What do we do if the increment (f.e.) contains a stmt expression, - // which contains a continue/break? CleanupScope ForScope(*this); // Evaluate the first part before the loop. @@ -555,14 +559,14 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { EmitStmt(S.getBody()); } - BreakContinueStack.pop_back(); - // If there is an increment, emit it next. if (S.getInc()) { EmitBlock(IncBlock); EmitStmt(S.getInc()); } + BreakContinueStack.pop_back(); + // Finally, branch back up to the condition for the next iteration. if (CondCleanup) { // Branch to the cleanup block. @@ -604,7 +608,20 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { // FIXME: Clean this up by using an LValue for ReturnTemp, // EmitStoreThroughLValue, and EmitAnyExpr. - if (!ReturnValue) { + if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable() && + !Target.useGlobalsForAutomaticVariables()) { + // Apply the named return value optimization for this return statement, + // which means doing nothing: the appropriate result has already been + // constructed into the NRVO variable. + + // If there is an NRVO flag for this variable, set it to 1 into indicate + // that the cleanup code should not destroy the variable. + if (llvm::Value *NRVOFlag = NRVOFlags[S.getNRVOCandidate()]) { + const llvm::Type *BoolTy = llvm::Type::getInt1Ty(VMContext); + llvm::Value *One = llvm::ConstantInt::get(BoolTy, 1); + Builder.CreateStore(One, NRVOFlag); + } + } else if (!ReturnValue) { // Make sure not to return anything, but evaluate the expression // for side effects. if (RV) diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index 15e564810f83..61c74230e118 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -378,7 +378,7 @@ CodeGenVTables::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, D1(printf("vtt %s\n", RD->getNameAsCString())); - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true); if (GV == 0 || GV->isDeclaration()) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 159753aa359c..0f023e63ae54 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -2548,7 +2548,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, getMangleContext().mangleThunk(MD, Thunk, Name); const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(MD); - return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); + return GetOrCreateLLVMFunction(Name, Ty, GD); } static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, @@ -2641,10 +2641,9 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, E = MD->param_end(); I != E; ++I) { ParmVarDecl *Param = *I; QualType ArgType = Param->getType(); + RValue Arg = EmitDelegateCallArg(Param); - // FIXME: Declaring a DeclRefExpr on the stack is kinda icky. - DeclRefExpr ArgExpr(Param, ArgType.getNonReferenceType(), SourceLocation()); - CallArgs.push_back(std::make_pair(EmitCallArg(&ArgExpr, ArgType), ArgType)); + CallArgs.push_back(std::make_pair(Arg, ArgType)); } // Get our callee. @@ -2657,8 +2656,15 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, CGM.getTypes().getFunctionInfo(ResultType, CallArgs, FPT->getExtInfo()); + // Determine whether we have a return value slot to use. + ReturnValueSlot Slot; + if (!ResultType->isVoidType() && + FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect && + hasAggregateLLVMType(CurFnInfo->getReturnType())) + Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified()); + // Now emit our call. - RValue RV = EmitCall(FnInfo, Callee, ReturnValueSlot(), CallArgs, MD); + RValue RV = EmitCall(FnInfo, Callee, Slot, CallArgs, MD); if (!Thunk.Return.isEmpty()) { // Emit the return adjustment. @@ -2701,7 +2707,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, RV = RValue::get(ReturnValue); } - if (!ResultType->isVoidType()) + if (!ResultType->isVoidType() && Slot.isNull()) EmitReturnOfRValue(RV, ResultType); FinishFunction(); @@ -2710,7 +2716,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, CXXThisDecl->Destroy(getContext()); // Set the right linkage. - Fn->setLinkage(CGM.getFunctionLinkage(MD)); + CGM.setFunctionLinkage(MD, Fn); // Set the right visibility. CGM.setGlobalVisibility(Fn, MD); @@ -2788,7 +2794,13 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { // Check if we've computed this information before. if (LayoutData) return; - + + // We may need to generate a definition for this vtable. + if (!isKeyFunctionInAnotherTU(CGM.getContext(), RD) && + RD->getTemplateSpecializationKind() + != TSK_ExplicitInstantiationDeclaration) + CGM.DeferredVTables.push_back(RD); + VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); // Add the VTable layout. @@ -3119,49 +3131,3 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, DC->getParent()->isTranslationUnit()) CGM.EmitFundamentalRTTIDescriptors(); } - -void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - const CXXRecordDecl *RD = MD->getParent(); - - // If the class doesn't have a vtable we don't need to emit one. - if (!RD->isDynamicClass()) - return; - - // Check if we need to emit thunks for this function. - if (MD->isVirtual()) - EmitThunks(GD); - - // Get the key function. - const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD); - - TemplateSpecializationKind RDKind = RD->getTemplateSpecializationKind(); - TemplateSpecializationKind MDKind = MD->getTemplateSpecializationKind(); - - if (KeyFunction) { - // We don't have the right key function. - if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) - return; - } else { - // If we have no key funcion and this is a explicit instantiation declaration, - // we will produce a vtable at the explicit instantiation. We don't need one - // here. - if (RDKind == clang::TSK_ExplicitInstantiationDeclaration) - return; - - // If this is an explicit instantiation of a method, we don't need a vtable. - // Since we have no key function, we will emit the vtable when we see - // a use, and just defining a function is not an use. - if (RDKind == TSK_ImplicitInstantiation && - MDKind == TSK_ExplicitInstantiationDefinition) - return; - } - - if (VTables.count(RD)) - return; - - if (RDKind == TSK_ImplicitInstantiation) - CGM.DeferredVTables.push_back(RD); - else - GenerateClassData(CGM.getVTableLinkage(RD), RD); -} diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h index 6c18ca83f091..e55377f2fa2f 100644 --- a/lib/CodeGen/CGVTables.h +++ b/lib/CodeGen/CGVTables.h @@ -272,9 +272,6 @@ class CodeGenVTables { /// EmitThunk - Emit a single thunk. void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk); - /// EmitThunks - Emit the associated thunks for the given global decl. - void EmitThunks(GlobalDecl GD); - /// ComputeVTableRelatedInformation - Compute and store all vtable related /// information (vtable layout, vbase offset offsets, thunks etc) for the /// given record decl. @@ -349,11 +346,10 @@ public: VTableAddressPointsMapTy& AddressPoints); llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD); - - // EmitVTableRelatedData - Will emit any thunks that the global decl might - // have, as well as the vtable itself if the global decl is the key function. - void EmitVTableRelatedData(GlobalDecl GD); + /// EmitThunks - Emit the associated thunks for the given global decl. + void EmitThunks(GlobalDecl GD); + /// GenerateClassData - Generate all the class data required to be generated /// upon definition of a KeyFunction. This includes the vtable, the /// rtti data structure and the VTT. diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index dfd2a391a4cf..a226400a3787 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -28,7 +28,10 @@ add_clang_library(clangCodeGen CodeGenFunction.cpp CodeGenModule.cpp CodeGenTypes.cpp + ItaniumCXXABI.cpp Mangle.cpp ModuleBuilder.cpp TargetInfo.cpp ) + +add_dependencies(clangCodeGen ClangStmtNodes) diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index d3bf1645a026..73de0fd77384 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -37,6 +37,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) LLVMPointerWidth = Target.getPointerWidth(0); Exceptions = getContext().getLangOptions().Exceptions; CatchUndefined = getContext().getLangOptions().CatchUndefined; + CGM.getMangleContext().startNewFunction(); } ASTContext &CodeGenFunction::getContext() const { @@ -472,7 +473,23 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type, CGM.ErrorUnsupported(S, Type, OmitOnError); } -void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { +void +CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { + // If the type contains a pointer to data member we can't memset it to zero. + // Instead, create a null constant and copy it to the destination. + if (CGM.getTypes().ContainsPointerToDataMember(Ty)) { + llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty); + + llvm::GlobalVariable *NullVariable = + new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(), + /*isConstant=*/true, + llvm::GlobalVariable::PrivateLinkage, + NullConstant, llvm::Twine()); + EmitAggregateCopy(DestPtr, NullVariable, Ty, /*isVolatile=*/false); + return; + } + + // Ignore empty classes in C++. if (getContext().getLangOptions().CPlusPlus) { if (const RecordType *RT = Ty->getAs<RecordType>()) { @@ -481,6 +498,9 @@ void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { } } + // Otherwise, just memset the whole thing to zero. This is legal + // because in LLVM, all default initializers (other than the ones we just + // handled above) are guaranteed to have a bit pattern of all zeros. const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); if (DestPtr->getType() != BP) DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 90a3ec4a4b10..ece275e7629e 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -67,6 +67,7 @@ namespace CodeGen { class CGDebugInfo; class CGFunctionInfo; class CGRecordLayout; + class CGBlockInfo; /// CodeGenFunction - This class organizes the per-function state that is used /// while generating LLVM code. @@ -107,6 +108,11 @@ public: bool Exceptions; bool CatchUndefined; + + /// \brief A mapping from NRVO variables to the flags used to indicate + /// when the NRVO has been applied to this variable. + llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags; + public: /// ObjCEHValueStack - Stack of Objective-C exception values, used for /// rethrows. @@ -496,18 +502,18 @@ public: std::vector<HelperInfo> *); llvm::Function *GenerateBlockFunction(const BlockExpr *BExpr, - const BlockInfo& Info, + CGBlockInfo &Info, const Decl *OuterFuncDecl, - llvm::DenseMap<const Decl*, llvm::Value*> ldm, - CharUnits &Size, CharUnits &Align, - llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls, - bool &subBlockHasCopyDispose); + llvm::DenseMap<const Decl*, llvm::Value*> ldm); - void BlockForwardSelf(); llvm::Value *LoadBlockStruct(); - CharUnits AllocateBlockDecl(const BlockDeclRefExpr *E); - llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E); + void AllocateBlockCXXThisPointer(const CXXThisExpr *E); + void AllocateBlockDecl(const BlockDeclRefExpr *E); + llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { + return GetAddrOfBlockDecl(E->getDecl(), E->isByRef()); + } + llvm::Value *GetAddrOfBlockDecl(const ValueDecl *D, bool ByRef); const llvm::Type *BuildByRefType(const ValueDecl *D); void GenerateCode(GlobalDecl GD, llvm::Function *Fn); @@ -531,7 +537,8 @@ public: /// GenerateThunk - Generate a thunk for the given method. void GenerateThunk(llvm::Function *Fn, GlobalDecl GD, const ThunkInfo &Thunk); - void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type); + void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type, + FunctionArgList &Args); /// InitializeVTablePointer - Initialize the vtable pointer of the given /// subobject. @@ -554,8 +561,6 @@ public: void InitializeVTablePointers(const CXXRecordDecl *ClassDecl); - void SynthesizeCXXCopyConstructor(const FunctionArgList &Args); - /// EmitDtorEpilogue - Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes in /// reverse order of their construction. @@ -725,8 +730,6 @@ public: void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr, QualType EltTy, bool isVolatile=false); - void EmitAggregateClear(llvm::Value *DestPtr, QualType Ty); - /// StartBlock - Start new block named N. If insert block is a dummy block /// then reuse it. void StartBlock(const char *N); @@ -744,8 +747,10 @@ public: llvm::BlockAddress *GetAddrOfLabel(const LabelStmt *L); llvm::BasicBlock *GetIndirectGotoBlock(); - /// EmitMemSetToZero - Generate code to memset a value of the given type to 0. - void EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty); + /// EmitNullInitialization - Generate code to set a value of the given type to + /// null, If the type contains data member pointers, they will be initialized + /// to -1 in accordance with the Itanium C++ ABI. + void EmitNullInitialization(llvm::Value *DestPtr, QualType Ty); // EmitVAArg - Generate code to get an argument from the passed in pointer // and update it accordingly. The return value is a pointer to the argument. @@ -802,14 +807,6 @@ public: const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl); - void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue, - llvm::Value *SrcValue, - const ConstantArrayType *Array, - const CXXRecordDecl *ClassDecl); - - void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, - const CXXRecordDecl *ClassDecl); - void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, const FunctionArgList &Args); @@ -940,6 +937,7 @@ public: void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S); void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S); + llvm::Constant *getUnwindResumeOrRethrowFn(); struct CXXTryStmtInfo { llvm::BasicBlock *SavedLandingPad; llvm::BasicBlock *HandlerBlock; @@ -1056,6 +1054,9 @@ public: llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); + LValue EmitLValueForAnonRecordField(llvm::Value* Base, + const FieldDecl* Field, + unsigned CVRQualifiers); LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field, unsigned CVRQualifiers); @@ -1151,9 +1152,12 @@ public: llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E); llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E); llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E); - RValue EmitObjCMessageExpr(const ObjCMessageExpr *E); - RValue EmitObjCPropertyGet(const Expr *E); - RValue EmitObjCSuperPropertyGet(const Expr *Exp, const Selector &S); + RValue EmitObjCMessageExpr(const ObjCMessageExpr *E, + ReturnValueSlot Return = ReturnValueSlot()); + RValue EmitObjCPropertyGet(const Expr *E, + ReturnValueSlot Return = ReturnValueSlot()); + RValue EmitObjCSuperPropertyGet(const Expr *Exp, const Selector &S, + ReturnValueSlot Return = ReturnValueSlot()); void EmitObjCPropertySet(const Expr *E, RValue Src); void EmitObjCSuperPropertySet(const Expr *E, const Selector &S, RValue Src); @@ -1298,6 +1302,11 @@ public: /// EmitCallArg - Emit a single call argument. RValue EmitCallArg(const Expr *E, QualType ArgType); + /// EmitDelegateCallArg - We are performing a delegate call; that + /// is, the current function is delegating to another one. Produce + /// a r-value suitable for passing the given parameter. + RValue EmitDelegateCallArg(const VarDecl *Param); + private: void EmitReturnOfRValue(RValue RV, QualType Ty); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index cc90a2855dee..103024c32392 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -48,7 +48,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()), - MangleCtx(C, diags), VTables(*this), Runtime(0), + VTables(*this), Runtime(0), ABI(0), CFConstantStringClassRef(0), NSConstantStringClassRef(0), VMContext(M.getContext()) { @@ -62,12 +62,17 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, else Runtime = CreateMacObjCRuntime(*this); + if (!Features.CPlusPlus) + ABI = 0; + else createCXXABI(); + // If debug info generation is enabled, create the CGDebugInfo object. DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(*this) : 0; } CodeGenModule::~CodeGenModule() { delete Runtime; + delete ABI; delete DebugInfo; } @@ -80,6 +85,11 @@ void CodeGenModule::createObjCRuntime() { Runtime = CreateMacObjCRuntime(*this); } +void CodeGenModule::createCXXABI() { + // For now, just create an Itanium ABI. + ABI = CreateItaniumCXXABI(*this); +} + void CodeGenModule::Release() { EmitDeferred(); EmitCXXGlobalInitFunc(); @@ -316,17 +326,6 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, == TSK_ExplicitInstantiationDeclaration) return CodeGenModule::GVA_C99Inline; - // If this is a virtual method and its class has a key method in another - // translation unit, we know that this method will be present in that - // translation unit. In this translation unit we will use this method - // only for inlining and analysis. This is the semantics of c99 inline. - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - const CXXRecordDecl *RD = MD->getParent(); - if (MD->isVirtual() && - CodeGenVTables::isKeyFunctionInAnotherTU(Context, RD)) - return CodeGenModule::GVA_C99Inline; - } - return CodeGenModule::GVA_CXXInline; } @@ -372,7 +371,6 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { /// variables (these details are set in EmitGlobalVarDefinition for variables). void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, llvm::GlobalValue *GV) { - GV->setLinkage(getFunctionLinkage(D)); SetCommonAttributes(D, GV); } @@ -515,9 +513,14 @@ void CodeGenModule::EmitDeferred() { GlobalDecl D = DeferredDeclsToEmit.back(); DeferredDeclsToEmit.pop_back(); - // Look it up to see if it was defined with a stronger definition (e.g. an - // extern inline function with a strong function redefinition). If so, - // just ignore the deferred decl. + // Check to see if we've already emitted this. This is necessary + // for a couple of reasons: first, decls can end up in the + // deferred-decls queue multiple times, and second, decls can end + // up with definitions in unusual ways (e.g. by an extern inline + // function acquiring a strong function redefinition). Just + // ignore these cases. + // + // TODO: That said, looking this up multiple times is very wasteful. MangleBuffer Name; getMangledName(Name, D); llvm::GlobalValue *CGRef = GetGlobalValue(Name); @@ -526,6 +529,11 @@ void CodeGenModule::EmitDeferred() { if (!CGRef->isDeclaration()) continue; + // GlobalAlias::isDeclaration() defers to the aliasee, but for our + // purposes an alias counts as a definition. + if (isa<llvm::GlobalAlias>(CGRef)) + continue; + // Otherwise, emit the definition and move on to the next one. EmitGlobalDefinition(D); } @@ -727,8 +735,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); - if (isa<CXXMethodDecl>(D)) - getVTables().EmitVTableRelatedData(GD); + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isVirtual()) + getVTables().EmitThunks(GD); if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) return EmitCXXConstructor(CD, GD.getCtorType()); @@ -984,6 +993,11 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { EmitGlobalVarDefinition(D); } +void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) { + if (DefinitionRequired) + getVTables().GenerateClassData(getVTableLinkage(Class), Class); +} + llvm::GlobalVariable::LinkageTypes CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) @@ -1101,10 +1115,12 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type"); Init = EmitNullConstant(D->getType()); } else { - Init = EmitConstantExpr(InitExpr, D->getType()); - + Init = EmitConstantExpr(InitExpr, D->getType()); if (!Init) { QualType T = InitExpr->getType(); + if (D->getType()->isReferenceType()) + T = D->getType(); + if (getLangOptions().CPlusPlus) { EmitCXXGlobalVarDeclInitFunc(D); Init = EmitNullConstant(T); @@ -1333,6 +1349,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { } llvm::Function *Fn = cast<llvm::Function>(Entry); + setFunctionLinkage(D, Fn); CodeGenFunction(*this).GenerateCode(D, Fn); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 93d8ddf3e485..319744c4be3d 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -22,6 +22,7 @@ #include "CGCall.h" #include "CGCXX.h" #include "CGVTables.h" +#include "CGCXXABI.h" #include "CodeGenTypes.h" #include "GlobalDecl.h" #include "Mangle.h" @@ -90,13 +91,13 @@ class CodeGenModule : public BlockModule { mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; Diagnostic &Diags; CodeGenTypes Types; - MangleContext MangleCtx; /// VTables - Holds information about C++ vtables. CodeGenVTables VTables; friend class CodeGenVTables; CGObjCRuntime* Runtime; + CXXABI* ABI; CGDebugInfo* DebugInfo; // WeakRefReferences - A set of references that have only been seen via @@ -153,6 +154,8 @@ class CodeGenModule : public BlockModule { /// Lazily create the Objective-C runtime void createObjCRuntime(); + /// Lazily create the C++ ABI + void createCXXABI(); llvm::LLVMContext &VMContext; public: @@ -175,6 +178,16 @@ public: /// been configured. bool hasObjCRuntime() { return !!Runtime; } + /// getCXXABI() - Return a reference to the configured + /// C++ ABI. + CXXABI &getCXXABI() { + if (!ABI) createCXXABI(); + return *ABI; + } + + /// hasCXXABI() - Return true iff a C++ ABI has been configured. + bool hasCXXABI() { return !!ABI; } + llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) { return StaticLocalDeclMap[VD]; } @@ -189,7 +202,10 @@ public: const LangOptions &getLangOptions() const { return Features; } llvm::Module &getModule() const { return TheModule; } CodeGenTypes &getTypes() { return Types; } - MangleContext &getMangleContext() { return MangleCtx; } + MangleContext &getMangleContext() { + if (!ABI) createCXXABI(); + return ABI->getMangleContext(); + } CodeGenVTables &getVTables() { return VTables; } Diagnostic &getDiags() const { return Diags; } const llvm::TargetData &getTargetData() const { return TheTargetData; } @@ -413,6 +429,7 @@ public: void getMangledName(MangleBuffer &Buffer, GlobalDecl D); void getMangledName(MangleBuffer &Buffer, const NamedDecl *ND); + void getMangledName(MangleBuffer &Buffer, const BlockDecl *BD); void getMangledCXXCtorName(MangleBuffer &Buffer, const CXXConstructorDecl *D, CXXCtorType Type); @@ -422,6 +439,8 @@ public: void EmitTentativeDefinition(const VarDecl *D); + void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired); + enum GVALinkage { GVA_Internal, GVA_C99Inline, @@ -434,6 +453,10 @@ public: llvm::GlobalVariable::LinkageTypes getFunctionLinkage(const FunctionDecl *FD); + void setFunctionLinkage(const FunctionDecl *FD, llvm::GlobalValue *V) { + V->setLinkage(getFunctionLinkage(FD)); + } + /// getVTableLinkage - Return the appropriate linkage for the vtable, VTT, /// and type information of the given class. static llvm::GlobalVariable::LinkageTypes diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index f53dd83d7035..a46dc726a45b 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -322,6 +322,9 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { true); } + case Type::ObjCObject: + return ConvertTypeRecursive(cast<ObjCObjectType>(Ty).getBaseType()); + case Type::ObjCInterface: { // Objective-C interfaces are always opaque (outside of the // runtime, which can do whatever it likes); we never refine @@ -467,3 +470,32 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *TD) const { assert(Layout && "Unable to find record layout information for type"); return *Layout; } + +bool CodeGenTypes::ContainsPointerToDataMember(QualType T) { + // No need to check for member pointers when not compiling C++. + if (!Context.getLangOptions().CPlusPlus) + return false; + + T = Context.getBaseElementType(T); + + if (const RecordType *RT = T->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + + return ContainsPointerToDataMember(RD); + } + + if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) + return !MPT->getPointeeType()->isFunctionType(); + + return false; +} + +bool CodeGenTypes::ContainsPointerToDataMember(const CXXRecordDecl *RD) { + + // FIXME: It would be better if there was a way to explicitly compute the + // record layout instead of converting to a type. + ConvertTagDeclType(RD); + + const CGRecordLayout &Layout = getCGRecordLayout(RD); + return Layout.containsPointerToDataMember(); +} diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 10e71e2a03fa..fc28c3ae33f4 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -186,6 +186,14 @@ public: // These are internal details of CGT that shouldn't be used externally. /// argument types it would be passed as on the provided vector \arg /// ArgTys. See ABIArgInfo::Expand. void GetExpandedTypes(QualType Ty, std::vector<const llvm::Type*> &ArgTys); + + /// ContainsPointerToDataMember - Return whether the given type contains a + /// pointer to a data member. + bool ContainsPointerToDataMember(QualType T); + + /// ContainsPointerToDataMember - Return whether the record decl contains a + /// pointer to a data member. + bool ContainsPointerToDataMember(const CXXRecordDecl *RD); }; } // end namespace CodeGen diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp new file mode 100644 index 000000000000..98db75ea2b46 --- /dev/null +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -0,0 +1,39 @@ +//===------- ItaniumCXXABI.cpp - Emit LLVM Code from ASTs for a Module ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides C++ code generation targetting the Itanium C++ ABI. The class +// in this file generates structures that follow the Itanium C++ ABI, which is +// documented at: +// http://www.codesourcery.com/public/cxx-abi/abi.html +// http://www.codesourcery.com/public/cxx-abi/abi-eh.html +//===----------------------------------------------------------------------===// + +#include "CGCXXABI.h" +#include "CodeGenModule.h" +#include "Mangle.h" + +using namespace clang; + +namespace { +class ItaniumCXXABI : public CodeGen::CXXABI { + CodeGen::MangleContext MangleCtx; +public: + ItaniumCXXABI(CodeGen::CodeGenModule &CGM) : + MangleCtx(CGM.getContext(), CGM.getDiags()) { } + + CodeGen::MangleContext &getMangleContext() { + return MangleCtx; + } +}; +} + +CodeGen::CXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { + return new ItaniumCXXABI(CGM); +} + diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 8658cfb0282c..6c2a64898fee 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -36,6 +36,57 @@ using namespace clang; using namespace CodeGen; +MiscNameMangler::MiscNameMangler(MangleContext &C, + llvm::SmallVectorImpl<char> &Res) + : Context(C), Out(Res) { } + +void MiscNameMangler::mangleBlock(const BlockDecl *BD) { + // Mangle the context of the block. + // FIXME: We currently mimic GCC's mangling scheme, which leaves much to be + // desired. Come up with a better mangling scheme. + const DeclContext *DC = BD->getDeclContext(); + while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) + DC = DC->getParent(); + if (DC->isFunctionOrMethod()) { + Out << "__"; + if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) + mangleObjCMethodName(Method); + else { + const NamedDecl *ND = cast<NamedDecl>(DC); + if (IdentifierInfo *II = ND->getIdentifier()) + Out << II->getName(); + else { + // FIXME: We were doing a mangleUnqualifiedName() before, but that's + // a private member of a class that will soon itself be private to the + // Itanium C++ ABI object. What should we do now? Right now, I'm just + // calling the mangleName() method on the MangleContext; is there a + // better way? + llvm::SmallString<64> Buffer; + Context.mangleName(ND, Buffer); + Out << Buffer; + } + } + Out << "_block_invoke_" << Context.getBlockId(BD, true); + } else { + Out << "__block_global_" << Context.getBlockId(BD, false); + } +} + +void MiscNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + llvm::SmallString<64> Name; + llvm::raw_svector_ostream OS(Name); + + 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 << ')'; + OS << ' ' << MD->getSelector().getAsString() << ']'; + + Out << OS.str().size() << OS.str(); +} + namespace { static const DeclContext *GetLocalClassFunctionDeclContext( @@ -107,7 +158,8 @@ public: void mangleFunctionEncoding(const FunctionDecl *FD); void mangleName(const NamedDecl *ND); void mangleType(QualType T); - + void mangleNameOrStandardSubstitution(const NamedDecl *ND); + private: bool mangleSubstitution(const NamedDecl *ND); bool mangleSubstitution(QualType T); @@ -714,8 +766,9 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { const DeclContext *DC = ND->getDeclContext(); Out << 'Z'; - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) - mangleObjCMethodName(MD); + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) { + mangleObjCMethodName(MD); + } else if (const DeclContext *CDC = GetLocalClassFunctionDeclContext(DC)) { mangleFunctionEncoding(cast<FunctionDecl>(CDC)); Out << 'E'; @@ -752,6 +805,14 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { if (DC->isTranslationUnit()) return; + if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) { + manglePrefix(DC->getParent(), NoFunction); + llvm::SmallString<64> Name; + Context.mangleBlock(Block, Name); + Out << Name.size() << Name; + return; + } + if (mangleSubstitution(cast<NamedDecl>(DC))) return; @@ -762,8 +823,10 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); mangleTemplateArgs(*TemplateParameters, *TemplateArgs); } - else if(NoFunction && isa<FunctionDecl>(DC)) + else if(NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))) return; + else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) + mangleObjCMethodName(Method); else { manglePrefix(DC->getParent(), NoFunction); mangleUnqualifiedName(cast<NamedDecl>(DC)); @@ -942,18 +1005,9 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { } void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { - llvm::SmallString<64> Name; - llvm::raw_svector_ostream OS(Name); - - 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 << ')'; - OS << ' ' << MD->getSelector().getAsString() << ']'; - - Out << OS.str().size() << OS.str(); + llvm::SmallString<64> Buffer; + MiscNameMangler(Context, Buffer).mangleObjCMethodName(MD); + Out << Buffer; } void CXXNameMangler::mangleType(QualType T) { @@ -989,6 +1043,11 @@ void CXXNameMangler::mangleType(QualType T) { addSubstitution(T); } +void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) { + if (!mangleStandardSubstitution(ND)) + mangleName(ND); +} + void CXXNameMangler::mangleType(const BuiltinType *T) { // <type> ::= <builtin-type> // <builtin-type> ::= v # void @@ -1206,6 +1265,12 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { mangleSourceName(T->getDecl()->getIdentifier()); } +void CXXNameMangler::mangleType(const ObjCObjectType *T) { + // We don't allow overloading by different protocol qualification, + // so mangling them isn't necessary. + mangleType(T->getBaseType()); +} + void CXXNameMangler::mangleType(const BlockPointerType *T) { Out << "U13block_pointer"; mangleType(T->getPointeeType()); @@ -1369,7 +1434,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { #define EXPR(Type, Base) #define STMT(Type, Base) \ case Expr::Type##Class: -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" llvm_unreachable("unexpected statement kind"); break; @@ -2027,6 +2092,12 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, Mangler.mangle(D); } +void MangleContext::mangleBlock(const BlockDecl *BD, + llvm::SmallVectorImpl<char> &Res) { + MiscNameMangler Mangler(*this, Res); + Mangler.mangleBlock(BD); +} + void MangleContext::mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, llvm::SmallVectorImpl<char> &Res) { @@ -2089,7 +2160,7 @@ void MangleContext::mangleCXXVTable(const CXXRecordDecl *RD, // <special-name> ::= TV <type> # virtual table CXXNameMangler Mangler(*this, Res); Mangler.getStream() << "_ZTV"; - Mangler.mangleName(RD); + Mangler.mangleNameOrStandardSubstitution(RD); } void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD, @@ -2097,7 +2168,7 @@ void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD, // <special-name> ::= TT <type> # VTT structure CXXNameMangler Mangler(*this, Res); Mangler.getStream() << "_ZTT"; - Mangler.mangleName(RD); + Mangler.mangleNameOrStandardSubstitution(RD); } void MangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, @@ -2106,10 +2177,10 @@ void MangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, // <special-name> ::= TC <type> <offset number> _ <base type> CXXNameMangler Mangler(*this, Res); Mangler.getStream() << "_ZTC"; - Mangler.mangleName(RD); + Mangler.mangleNameOrStandardSubstitution(RD); Mangler.getStream() << Offset; Mangler.getStream() << '_'; - Mangler.mangleName(Type); + Mangler.mangleNameOrStandardSubstitution(Type); } void MangleContext::mangleCXXRTTI(QualType Ty, diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index da3626fc5d37..f1c5358bdd85 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -23,14 +23,17 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" namespace clang { class ASTContext; + class BlockDecl; class CXXConstructorDecl; class CXXDestructorDecl; class CXXMethodDecl; class FunctionDecl; class NamedDecl; + class ObjCMethodDecl; class VarDecl; namespace CodeGen { @@ -63,7 +66,7 @@ private: llvm::StringRef String; llvm::SmallString<256> Buffer; }; - + /// MangleContext - Context for tracking state which persists across multiple /// calls to the C++ name mangler. class MangleContext { @@ -73,6 +76,8 @@ class MangleContext { llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds; unsigned Discriminator; llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; + llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds; + llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds; public: explicit MangleContext(ASTContext &Context, @@ -83,6 +88,8 @@ public: Diagnostic &getDiags() const { return Diags; } + void startNewFunction() { LocalBlockIds.clear(); } + uint64_t getAnonymousStructId(const TagDecl *TD) { std::pair<llvm::DenseMap<const TagDecl *, uint64_t>::iterator, bool> Result = @@ -90,31 +97,42 @@ public: return Result.first->second; } + unsigned getBlockId(const BlockDecl *BD, bool Local) { + llvm::DenseMap<const BlockDecl *, unsigned> &BlockIds + = Local? LocalBlockIds : GlobalBlockIds; + std::pair<llvm::DenseMap<const BlockDecl *, unsigned>::iterator, bool> + Result = BlockIds.insert(std::make_pair(BD, BlockIds.size())); + return Result.first->second; + } + /// @name Mangler Entry Points /// @{ bool shouldMangleDeclName(const NamedDecl *D); - - void mangleName(const NamedDecl *D, llvm::SmallVectorImpl<char> &); - void mangleThunk(const CXXMethodDecl *MD, - const ThunkInfo &Thunk, - llvm::SmallVectorImpl<char> &); - void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, + virtual void mangleName(const NamedDecl *D, llvm::SmallVectorImpl<char> &); + virtual void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, llvm::SmallVectorImpl<char> &); - void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &); - void mangleCXXVTable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &); - void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &); - void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, - const CXXRecordDecl *Type, - llvm::SmallVectorImpl<char> &); - void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &); - void mangleCXXRTTIName(QualType T, llvm::SmallVectorImpl<char> &); - void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, - llvm::SmallVectorImpl<char> &); - void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, - llvm::SmallVectorImpl<char> &); - + virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + llvm::SmallVectorImpl<char> &); + virtual void mangleGuardVariable(const VarDecl *D, + llvm::SmallVectorImpl<char> &); + virtual void mangleCXXVTable(const CXXRecordDecl *RD, + llvm::SmallVectorImpl<char> &); + virtual void mangleCXXVTT(const CXXRecordDecl *RD, + llvm::SmallVectorImpl<char> &); + virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + llvm::SmallVectorImpl<char> &); + virtual void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &); + virtual void mangleCXXRTTIName(QualType T, llvm::SmallVectorImpl<char> &); + virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + llvm::SmallVectorImpl<char> &); + virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + llvm::SmallVectorImpl<char> &); + void mangleBlock(const BlockDecl *BD, llvm::SmallVectorImpl<char> &); + void mangleInitDiscriminator() { Discriminator = 0; } @@ -130,7 +148,23 @@ public: } /// @} }; + +/// MiscNameMangler - Mangles Objective-C method names and blocks. +class MiscNameMangler { + MangleContext &Context; + llvm::raw_svector_ostream Out; + ASTContext &getASTContext() const { return Context.getASTContext(); } + +public: + MiscNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res); + + llvm::raw_svector_ostream &getStream() { return Out; } + + void mangleBlock(const BlockDecl *BD); + void mangleObjCMethodName(const ObjCMethodDecl *MD); +}; + } } diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index 1e1edc1c482f..9905ca6f1dc8 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -89,6 +89,13 @@ namespace { Builder->EmitTentativeDefinition(D); } + + virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) { + if (Diags.hasErrorOccurred()) + return; + + Builder->EmitVTable(RD, DefinitionRequired); + } }; } diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index e1fdf86eb026..b29d3cb00c4a 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -23,6 +23,18 @@ using namespace clang; using namespace CodeGen; +static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder, + llvm::Value *Array, + llvm::Value *Value, + unsigned FirstIndex, + unsigned LastIndex) { + // Alternatively, we could emit this as a loop in the source. + for (unsigned I = FirstIndex; I <= LastIndex; ++I) { + llvm::Value *Cell = Builder.CreateConstInBoundsGEP1_32(Array, I); + Builder.CreateStore(Value, Cell); + } +} + ABIInfo::~ABIInfo() {} void ABIArgInfo::dump() const { @@ -71,6 +83,17 @@ static bool isEmptyField(ASTContext &Context, const FieldDecl *FD, while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) FT = AT->getElementType(); + const RecordType *RT = FT->getAs<RecordType>(); + if (!RT) + return false; + + // C++ record fields are never empty, at least in the Itanium ABI. + // + // FIXME: We should use a predicate for whether this behavior is true in the + // current ABI. + if (isa<CXXRecordDecl>(RT->getDecl())) + return false; + return isEmptyRecord(Context, FT, AllowArrays); } @@ -84,6 +107,14 @@ static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return false; + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), + e = CXXRD->bases_end(); i != e; ++i) + if (!isEmptyRecord(Context, i->getType(), true)) + return false; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) if (!isEmptyField(Context, *i, AllowArrays)) @@ -130,6 +161,28 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { return 0; const Type *Found = 0; + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), + e = CXXRD->bases_end(); i != e; ++i) { + // Ignore empty records. + if (isEmptyRecord(Context, i->getType(), true)) + continue; + + // If we already found an element then this isn't a single-element struct. + if (Found) + return 0; + + // If this is non-empty and not a single element struct, the composite + // cannot be a single element struct. + Found = isSingleElementStruct(i->getType(), Context); + if (!Found) + return 0; + } + } + + // Check for single element. for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { const FieldDecl *FD = *i; @@ -164,7 +217,7 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { } static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) { - if (!Ty->getAs<BuiltinType>() && !Ty->isAnyPointerType() && + if (!Ty->getAs<BuiltinType>() && !Ty->hasPointerRepresentation() && !Ty->isAnyComplexType() && !Ty->isEnumeralType() && !Ty->isBlockPointerType()) return false; @@ -212,23 +265,6 @@ static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) { return true; } -static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) { - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - const FieldDecl *FD = *i; - - if (FD->getType()->isVectorType() && - Context.getTypeSize(FD->getType()) >= 128) - return true; - - if (const RecordType* RT = FD->getType()->getAs<RecordType>()) - if (typeContainsSSEVector(RT->getDecl(), Context)) - return true; - } - - return false; -} - namespace { /// DefaultABIInfo - The default implementation for ABI specific /// details. This implementation provides information which results in @@ -363,10 +399,11 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, return true; } - // If this is a builtin, pointer, enum, or complex type, it is ok. - if (Ty->getAs<BuiltinType>() || Ty->isAnyPointerType() || + // If this is a builtin, pointer, enum, complex type, member pointer, or + // member function pointer it is ok. + if (Ty->getAs<BuiltinType>() || Ty->hasPointerRepresentation() || Ty->isAnyComplexType() || Ty->isEnumeralType() || - Ty->isBlockPointerType()) + Ty->isBlockPointerType() || Ty->isMemberPointerType()) return true; // Arrays are treated like records. @@ -596,20 +633,14 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( // 0-7 are the eight integer registers; the order is different // on Darwin (for EH), but the range is the same. // 8 is %eip. - for (unsigned I = 0, E = 9; I != E; ++I) { - llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I); - Builder.CreateStore(Four8, Slot); - } + AssignToArrayRange(Builder, Address, Four8, 0, 8); if (CGF.CGM.isTargetDarwin()) { // 12-16 are st(0..4). Not sure why we stop at 4. // These have size 16, which is sizeof(long double) on // platforms with 8-byte alignment for that type. llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16); - for (unsigned I = 12, E = 17; I != E; ++I) { - llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I); - Builder.CreateStore(Sixteen8, Slot); - } + AssignToArrayRange(Builder, Address, Sixteen8, 12, 16); } else { // 9 is %eflags, which doesn't get a size on Darwin for some @@ -620,11 +651,8 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( // These have size 12, which is sizeof(long double) on // platforms with 4-byte alignment for that type. llvm::Value *Twelve8 = llvm::ConstantInt::get(i8, 12); - for (unsigned I = 11, E = 17; I != E; ++I) { - llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I); - Builder.CreateStore(Twelve8, Slot); - } - } + AssignToArrayRange(Builder, Address, Twelve8, 11, 16); + } return false; } @@ -733,12 +761,9 @@ public: const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); - // 0-16 are the 16 integer registers. - // 17 is %rip. - for (unsigned I = 0, E = 17; I != E; ++I) { - llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I); - Builder.CreateStore(Eight8, Slot); - } + // 0-15 are the 16 integer registers. + // 16 is %rip. + AssignToArrayRange(Builder, Address, Eight8, 0, 16); return false; } @@ -828,6 +853,11 @@ void X86_64ABIInfo::classify(QualType Ty, classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi); } else if (Ty->hasPointerRepresentation()) { Current = Integer; + } else if (Ty->isMemberPointerType()) { + if (Ty->isMemberFunctionPointerType()) + Lo = Hi = Integer; + else + Current = Integer; } else if (const VectorType *VT = Ty->getAs<VectorType>()) { uint64_t Size = Context.getTypeSize(VT); if (Size == 32) { @@ -1661,16 +1691,10 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, 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); - } + AssignToArrayRange(Builder, Address, Four8, 0, 31); // 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); - } + AssignToArrayRange(Builder, Address, Eight8, 32, 63); // 64-76 are various 4-byte special-purpose registers: // 64: mq @@ -1679,26 +1703,17 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, // 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); - } + AssignToArrayRange(Builder, Address, Four8, 64, 76); // 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); - } + AssignToArrayRange(Builder, Address, Sixteen8, 77, 108); // 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); - } + AssignToArrayRange(Builder, Address, Four8, 109, 113); return false; } @@ -2123,6 +2138,56 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D, } } +// MIPS ABI Implementation. This works for both little-endian and +// big-endian variants. +namespace { +class MIPSTargetCodeGenInfo : public TargetCodeGenInfo { +public: + MIPSTargetCodeGenInfo(): TargetCodeGenInfo(new DefaultABIInfo()) {} + + int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const { + return 29; + } + + bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const; +}; +} + +bool +MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const { + // This information comes from gcc's implementation, which seems to + // as canonical as it gets. + + CodeGen::CGBuilderTy &Builder = CGF.Builder; + llvm::LLVMContext &Context = CGF.getLLVMContext(); + + // Everything on MIPS is 4 bytes. Double-precision FP registers + // are aliased to pairs of single-precision FP registers. + const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); + + // 0-31 are the general purpose registers, $0 - $31. + // 32-63 are the floating-point registers, $f0 - $f31. + // 64 and 65 are the multiply/divide registers, $hi and $lo. + // 66 is the (notional, I think) register for signal-handler return. + AssignToArrayRange(Builder, Address, Four8, 0, 65); + + // 67-74 are the floating-point status registers, $fcc0 - $fcc7. + // They are one bit wide and ignored here. + + // 80-111 are the coprocessor 0 registers, $c0r0 - $c0r31. + // (coprocessor 1 is the FP unit) + // 112-143 are the coprocessor 2 registers, $c2r0 - $c2r31. + // 144-175 are the coprocessor 3 registers, $c3r0 - $c3r31. + // 176-181 are the DSP accumulator registers. + AssignToArrayRange(Builder, Address, Four8, 80, 181); + + return false; +} + + const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const { if (TheTargetCodeGenInfo) return *TheTargetCodeGenInfo; @@ -2135,6 +2200,10 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const { default: return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo); + case llvm::Triple::mips: + case llvm::Triple::mipsel: + return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo()); + case llvm::Triple::arm: case llvm::Triple::thumb: // FIXME: We want to know the float calling convention as well. diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index 95805b016b1f..3d07431209e2 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -9,12 +9,14 @@ #include "clang/Driver/ArgList.h" #include "clang/Driver/Arg.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Option.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" +using namespace clang; using namespace clang::driver; void arg_iterator::SkipToNextArg() { @@ -108,6 +110,32 @@ bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const { return Default; } +llvm::StringRef ArgList::getLastArgValue(OptSpecifier Id, + llvm::StringRef Default) const { + if (Arg *A = getLastArg(Id)) + return A->getValue(*this); + return Default; +} + +int ArgList::getLastArgIntValue(OptSpecifier Id, int Default, + clang::Diagnostic &Diags) const { + int Res = Default; + + if (Arg *A = getLastArg(Id)) { + if (llvm::StringRef(A->getValue(*this)).getAsInteger(10, Res)) + Diags.Report(diag::err_drv_invalid_int_value) + << A->getAsString(*this) << A->getValue(*this); + } + + return Res; +} + +std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const { + llvm::SmallVector<const char *, 16> Values; + AddAllArgValues(Values, Id); + return std::vector<std::string>(Values.begin(), Values.end()); +} + void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const { if (Arg *A = getLastArg(Id)) { A->claim(); diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp new file mode 100644 index 000000000000..90c69ff0d62a --- /dev/null +++ b/lib/Driver/CC1AsOptions.cpp @@ -0,0 +1,39 @@ +//===--- CC1AsOptions.cpp - Clang Assembler Options Table -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/CC1AsOptions.h" +#include "clang/Driver/Option.h" +#include "clang/Driver/OptTable.h" +using namespace clang; +using namespace clang::driver; +using namespace clang::driver::options; +using namespace clang::driver::cc1asoptions; + +static const OptTable::Info CC1AsInfoTable[] = { +#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) \ + { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \ + OPT_##GROUP, OPT_##ALIAS }, +#include "clang/Driver/CC1AsOptions.inc" +}; + +namespace { + +class CC1AsOptTable : public OptTable { +public: + CC1AsOptTable() + : OptTable(CC1AsInfoTable, + sizeof(CC1AsInfoTable) / sizeof(CC1AsInfoTable[0])) {} +}; + +} + +OptTable *clang::driver::createCC1AsOptTable() { + return new CC1AsOptTable(); +} diff --git a/lib/Driver/CC1Options.cpp b/lib/Driver/CC1Options.cpp index 0e98bb9c113b..14cf0904c45b 100644 --- a/lib/Driver/CC1Options.cpp +++ b/lib/Driver/CC1Options.cpp @@ -1,4 +1,4 @@ -//===--- CC1Options.cpp - Clang CC1 Options Table -----------------------*-===// +//===--- CC1Options.cpp - Clang CC1 Options Table -------------------------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 7efcd8a8dde4..5af754d7d142 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(clangDriver Arg.cpp ArgList.cpp CC1Options.cpp + CC1AsOptions.cpp Compilation.cpp Driver.cpp DriverOptions.cpp @@ -20,4 +21,5 @@ add_clang_library(clangDriver Types.cpp ) -add_dependencies(clangDriver ClangDiagnosticDriver ClangDriverOptions ClangCC1Options) +add_dependencies(clangDriver ClangDiagnosticDriver ClangDriverOptions + ClangCC1Options ClangCC1AsOptions) diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 7371a930c337..da83803dd701 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -227,28 +227,31 @@ int Driver::ExecuteCompilation(const Compilation &C) const { // Remove temp files. C.CleanupFileList(C.getTempFiles()); - // If the compilation failed, remove result files as well. - if (Res != 0 && !C.getArgs().hasArg(options::OPT_save_temps)) + // If the command succeeded, we are done. + if (Res == 0) + return Res; + + // Otherwise, remove result files as well. + if (!C.getArgs().hasArg(options::OPT_save_temps)) C.CleanupFileList(C.getResultFiles(), true); // Print extra information about abnormal failures, if possible. - if (Res) { - // This is ad-hoc, but we don't want to be excessively noisy. If the result - // status was 1, assume the command failed normally. In particular, if it - // was the compiler then assume it gave a reasonable error code. Failures in - // other tools are less common, and they generally have worse diagnostics, - // so always print the diagnostic there. - const Action &Source = FailingCommand->getSource(); - - if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) { - // FIXME: See FIXME above regarding result code interpretation. - if (Res < 0) - Diag(clang::diag::err_drv_command_signalled) - << Source.getClassName() << -Res; - else - Diag(clang::diag::err_drv_command_failed) - << Source.getClassName() << Res; - } + // + // This is ad-hoc, but we don't want to be excessively noisy. If the result + // status was 1, assume the command failed normally. In particular, if it was + // the compiler then assume it gave a reasonable error code. Failures in other + // tools are less common, and they generally have worse diagnostics, so always + // print the diagnostic there. + const Tool &FailingTool = FailingCommand->getCreator(); + + if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) { + // FIXME: See FIXME above regarding result code interpretation. + if (Res < 0) + Diag(clang::diag::err_drv_command_signalled) + << FailingTool.getShortName() << -Res; + else + Diag(clang::diag::err_drv_command_failed) + << FailingTool.getShortName() << Res; } return Res; @@ -291,6 +294,14 @@ void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { OS << "Thread model: " << "posix" << '\n'; } +/// PrintDiagnosticCategories - Implement the --print-diagnostic-categories +/// option. +static void PrintDiagnosticCategories(llvm::raw_ostream &OS) { + for (unsigned i = 1; // Skip the empty category. + const char *CategoryName = Diagnostic::getCategoryNameFromID(i); ++i) + OS << i << ',' << CategoryName << '\n'; +} + bool Driver::HandleImmediateArgs(const Compilation &C) { // The order these options are handled in in gcc is all over the place, but we // don't expect inconsistencies w.r.t. that to matter in practice. @@ -299,6 +310,11 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { llvm::outs() << CLANG_VERSION_STRING "\n"; return false; } + + if (C.getArgs().hasArg(options::OPT__print_diagnostic_categories)) { + PrintDiagnosticCategories(llvm::outs()); + return false; + } if (C.getArgs().hasArg(options::OPT__help) || C.getArgs().hasArg(options::OPT__help_hidden)) { @@ -889,9 +905,16 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, // See if we should look for a compiler with an integrated assembler. We match // bottom up, so what we are actually looking for is an assembler job with a // compiler input. - if (C.getArgs().hasArg(options::OPT_integrated_as, + + // FIXME: This doesn't belong here, but ideally we will support static soon + // anyway. + bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) || + C.getArgs().hasArg(options::OPT_static) || + C.getArgs().hasArg(options::OPT_fapple_kext)); + bool IsIADefault = (TC->IsIntegratedAssemblerDefault() && !HasStatic); + if (C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, - TC->IsIntegratedAssemblerDefault()) && + IsIADefault) && !C.getArgs().hasArg(options::OPT_save_temps) && isa<AssembleJobAction>(JA) && Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) { diff --git a/lib/Driver/Tool.cpp b/lib/Driver/Tool.cpp index 781e0a702060..fe01531d9a2a 100644 --- a/lib/Driver/Tool.cpp +++ b/lib/Driver/Tool.cpp @@ -11,8 +11,10 @@ using namespace clang::driver; -Tool::Tool(const char *_Name, const ToolChain &TC) : Name(_Name), - TheToolChain(TC) { +Tool::Tool(const char *_Name, const char *_ShortName, + const ToolChain &TC) : Name(_Name), ShortName(_ShortName), + TheToolChain(TC) +{ } Tool::~Tool() { diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 1cd8ee186cae..abb55b07d106 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -11,6 +11,7 @@ #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" +#include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/HostInfo.h" @@ -190,6 +191,16 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const { else Key = JA.getKind(); + // FIXME: This doesn't belong here, but ideally we will support static soon + // anyway. + bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) || + C.getArgs().hasArg(options::OPT_static) || + C.getArgs().hasArg(options::OPT_fapple_kext)); + bool IsIADefault = IsIntegratedAssemblerDefault() && !HasStatic; + bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, + options::OPT_no_integrated_as, + IsIADefault); + Tool *&T = Tools[Key]; if (!T) { switch (Key) { @@ -203,8 +214,13 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const { case Action::PrecompileJobClass: case Action::CompileJobClass: T = new tools::darwin::Compile(*this); break; - case Action::AssembleJobClass: - T = new tools::darwin::Assemble(*this); break; + case Action::AssembleJobClass: { + if (UseIntegratedAs) + T = new tools::ClangAs(*this); + else + T = new tools::darwin::Assemble(*this); + break; + } case Action::LinkJobClass: T = new tools::darwin::Link(*this); break; case Action::LipoJobClass: diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 9acc950879d5..ad975bfe6dee 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -25,7 +25,7 @@ namespace toolchains { /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. -class VISIBILITY_HIDDEN Generic_GCC : public ToolChain { +class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { protected: mutable llvm::DenseMap<unsigned, Tool*> Tools; @@ -44,7 +44,7 @@ public: }; /// Darwin - The base Darwin tool chain. -class VISIBILITY_HIDDEN Darwin : public ToolChain { +class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { mutable llvm::DenseMap<unsigned, Tool*> Tools; /// Whether the information on the target has been initialized. @@ -56,7 +56,7 @@ class VISIBILITY_HIDDEN Darwin : public ToolChain { /// Whether we are targetting iPhoneOS target. mutable bool TargetIsIPhoneOS; - + /// The OS version we are targetting. mutable unsigned TargetVersion[3]; @@ -159,6 +159,11 @@ public: else return !isMacosxVersionLT(10, 6); } + virtual bool IsIntegratedAssemblerDefault() const { + // Default integrated assembler to on for x86. + return (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64); + } virtual bool IsObjCNonFragileABIDefault() const { // Non-fragile ABI is default for everything but i386. return getTriple().getArch() != llvm::Triple::x86; @@ -193,7 +198,7 @@ public: }; /// DarwinClang - The Darwin toolchain used by Clang. -class VISIBILITY_HIDDEN DarwinClang : public Darwin { +class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { public: DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, const unsigned (&DarwinVersion)[3]); @@ -211,7 +216,7 @@ public: }; /// DarwinGCC - The Darwin toolchain used by GCC. -class VISIBILITY_HIDDEN DarwinGCC : public Darwin { +class LLVM_LIBRARY_VISIBILITY DarwinGCC : public Darwin { /// GCC version to use. unsigned GCCVersion[3]; @@ -236,7 +241,7 @@ public: }; /// Darwin_Generic_GCC - Generic Darwin tool chain using gcc. -class VISIBILITY_HIDDEN Darwin_Generic_GCC : public Generic_GCC { +class LLVM_LIBRARY_VISIBILITY Darwin_Generic_GCC : public Generic_GCC { public: Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) {} @@ -244,35 +249,35 @@ public: virtual const char *GetDefaultRelocationModel() const { return "pic"; } }; -class VISIBILITY_HIDDEN AuroraUX : public Generic_GCC { +class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC { public: AuroraUX(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; }; -class VISIBILITY_HIDDEN OpenBSD : public Generic_GCC { +class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_GCC { public: OpenBSD(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; }; -class VISIBILITY_HIDDEN FreeBSD : public Generic_GCC { +class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_GCC { public: FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; }; -class VISIBILITY_HIDDEN DragonFly : public Generic_GCC { +class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_GCC { public: DragonFly(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; }; -class VISIBILITY_HIDDEN Linux : public Generic_GCC { +class LLVM_LIBRARY_VISIBILITY Linux : public Generic_GCC { public: Linux(const HostInfo &Host, const llvm::Triple& Triple); }; @@ -280,7 +285,7 @@ public: /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. -class VISIBILITY_HIDDEN TCEToolChain : public ToolChain { +class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { public: TCEToolChain(const HostInfo &Host, const llvm::Triple& Triple); ~TCEToolChain(); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 5a3916d19ea7..918f0d9715e7 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -21,7 +21,6 @@ #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" -#include "clang/Frontend/DiagnosticOptions.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" @@ -769,6 +768,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-E"); } else if (isa<AssembleJobAction>(JA)) { CmdArgs.push_back("-emit-obj"); + + // At -O0, we use -mrelax-all by default. + bool IsOpt = false; + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + IsOpt = !A->getOption().matches(options::OPT_O0); + if (Args.hasFlag(options::OPT_mrelax_all, + options::OPT_mno_relax_all, + !IsOpt)) + CmdArgs.push_back("-mrelax-all"); } else if (isa<PrecompileJobAction>(JA)) { // Use PCH if the user requested it, except for C++ (for now). bool UsePCH = D.CCCUsePCH; @@ -911,8 +919,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss)) CmdArgs.push_back("-mno-zero-initialized-in-bss"); - if (Args.hasArg(options::OPT_dA) || Args.hasArg(options::OPT_fverbose_asm)) + + // Decide whether to use verbose asm. Verbose assembly is the default on + // toolchains which have the integrated assembler on by default. + bool IsVerboseAsmDefault = getToolChain().IsIntegratedAssemblerDefault(); + if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, + IsVerboseAsmDefault) || + Args.hasArg(options::OPT_dA)) CmdArgs.push_back("-masm-verbose"); + if (Args.hasArg(options::OPT_fdebug_pass_structure)) { CmdArgs.push_back("-mdebug-pass"); CmdArgs.push_back("Structure"); @@ -979,6 +994,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("-fmath-errno"); + // Explicitly error on some things we know we don't support and can't just + // ignore. + types::ID InputType = Inputs[0].getType(); Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_MG)) || (Unsupported = Args.getLastArg(options::OPT_iframework)) || @@ -986,6 +1004,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(clang::diag::err_drv_clang_unsupported) << Unsupported->getOption().getName(); + if (types::isCXX(InputType) && + getToolChain().getTriple().getOS() == llvm::Triple::Darwin && + getToolChain().getTriple().getArch() == llvm::Triple::x86) { + if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext))) + D.Diag(clang::diag::err_drv_clang_unsupported_opt_cxx_darwin_i386) + << Unsupported->getOption().getName(); + } + Args.AddAllArgs(CmdArgs, options::OPT_v); Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); @@ -993,9 +1019,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Special case debug options to only pass -g to clang. This is // wrong. Args.ClaimAllArgs(options::OPT_g_Group); - Arg *Garg = Args.getLastArg(options::OPT_g_Group); - if (Garg && Garg != Args.getLastArg(options::OPT_g0)) - CmdArgs.push_back("-g"); + if (Arg *A = Args.getLastArg(options::OPT_g_Group)) + if (!A->getOption().matches(options::OPT_g0)) + CmdArgs.push_back("-g"); + + Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections); + Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections); Args.AddLastArg(CmdArgs, options::OPT_nostdinc); Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); @@ -1009,7 +1038,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // preprocessor. // // FIXME: Support -fpreprocessed - types::ID InputType = Inputs[0].getType(); if (types::getPreprocessedType(InputType) != types::TY_INVALID) AddPreprocessingOptions(D, Args, CmdArgs, Output, Inputs); @@ -1018,7 +1046,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (A->getOption().matches(options::OPT_O4)) CmdArgs.push_back("-O3"); - else if (A->getValue(Args)[0] == '\0') + else if (A->getOption().matches(options::OPT_O) && + A->getValue(Args)[0] == '\0') CmdArgs.push_back("-O2"); else A->render(Args, CmdArgs); @@ -1059,6 +1088,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_trigraphs); } + // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'. + if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) { + if (Asm->getOption().matches(options::OPT_fasm)) + CmdArgs.push_back("-fgnu-keywords"); + else + CmdArgs.push_back("-fno-gnu-keywords"); + } + if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_)) { CmdArgs.push_back("-ftemplate-depth"); CmdArgs.push_back(A->getValue(Args)); @@ -1083,20 +1120,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("19"); - CmdArgs.push_back("-fmacro-backtrace-limit"); - if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) + if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { + CmdArgs.push_back("-fmacro-backtrace-limit"); CmdArgs.push_back(A->getValue(Args)); - else - CmdArgs.push_back(Args.MakeArgString( - llvm::Twine(DiagnosticOptions::DefaultMacroBacktraceLimit))); - - CmdArgs.push_back("-ftemplate-backtrace-limit"); - if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) + } + + if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) { + CmdArgs.push_back("-ftemplate-backtrace-limit"); CmdArgs.push_back(A->getValue(Args)); - else - CmdArgs.push_back(Args.MakeArgString( - llvm::Twine(DiagnosticOptions::DefaultTemplateBacktraceLimit))); - + } + // Pass -fmessage-length=. CmdArgs.push_back("-fmessage-length"); if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { @@ -1265,6 +1298,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); } } + + // FIXME: -fobjc-nonfragile-abi2 is a transient option meant to expose + // features in testing. It will eventually be removed. + if (Args.hasArg(options::OPT_fobjc_nonfragile_abi2)) + CmdArgs.push_back("-fobjc-nonfragile-abi2"); } if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, @@ -1320,6 +1358,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_diagnostics_show_option)) CmdArgs.push_back("-fdiagnostics-show-option"); + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { + CmdArgs.push_back("-fdiagnostics-show-category"); + CmdArgs.push_back(A->getValue(Args)); + } + // Color diagnostics are the default, unless the terminal doesn't support // them. if (Args.hasFlag(options::OPT_fcolor_diagnostics, @@ -1451,6 +1495,67 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group); } +void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, + Job &Dest, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + ArgStringList CmdArgs; + + assert(Inputs.size() == 1 && "Unexpected number of inputs."); + const InputInfo &Input = Inputs[0]; + + // Invoke ourselves in -cc1as mode. + // + // FIXME: Implement custom jobs for internal actions. + CmdArgs.push_back("-cc1as"); + + // Add the "effective" target triple. + CmdArgs.push_back("-triple"); + std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); + + // Set the output mode, we currently only expect to be used as a real + // assembler. + CmdArgs.push_back("-filetype"); + CmdArgs.push_back("obj"); + + // At -O0, we use -mrelax-all by default. + bool IsOpt = false; + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + IsOpt = !A->getOption().matches(options::OPT_O0); + if (Args.hasFlag(options::OPT_mrelax_all, + options::OPT_mno_relax_all, + !IsOpt)) + CmdArgs.push_back("-mrelax-all"); + + // FIXME: Add -force_cpusubtype_ALL support, once we have it. + + // FIXME: Add -g support, once we have it. + + // FIXME: Add -static support, once we have it. + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, + options::OPT_Xassembler); + + assert(Output.isFilename() && "Unexpected lipo output."); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (Input.isPipe()) { + CmdArgs.push_back("-"); + } else { + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); + } + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath(C, "clang")); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); +} + void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, const InputInfo &Output, diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 091fec380622..d5e98dd24c48 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -26,7 +26,8 @@ namespace toolchains { namespace tools { - class VISIBILITY_HIDDEN Clang : public Tool { + /// \brief Clang compiler tool. + class LLVM_LIBRARY_VISIBILITY Clang : public Tool { void AddPreprocessingOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, @@ -38,7 +39,7 @@ namespace tools { void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; public: - Clang(const ToolChain &TC) : Tool("clang", TC) {} + Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -54,11 +55,32 @@ namespace tools { const char *LinkingOutput) const; }; + /// \brief Clang integrated assembler tool. + class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { + public: + ClangAs(const ToolChain &TC) : Tool("clang::as", + "clang integrated assembler", TC) {} + + virtual bool acceptsPipedInput() const { return true; } + virtual bool canPipeOutput() const { return true; } + virtual bool hasGoodDiagnostics() const { return true; } + virtual bool hasIntegratedAssembler() const { return false; } + virtual bool hasIntegratedCPP() const { return false; } + + virtual void ConstructJob(Compilation &C, const JobAction &JA, + Job &Dest, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const; + }; + /// gcc - Generic GCC tool implementations. namespace gcc { - class VISIBILITY_HIDDEN Common : public Tool { + class LLVM_LIBRARY_VISIBILITY Common : public Tool { public: - Common(const char *Name, const ToolChain &TC) : Tool(Name, TC) {} + Common(const char *Name, const char *ShortName, + const ToolChain &TC) : Tool(Name, ShortName, TC) {} virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, @@ -74,9 +96,10 @@ namespace gcc { }; - class VISIBILITY_HIDDEN Preprocess : public Common { + class LLVM_LIBRARY_VISIBILITY Preprocess : public Common { public: - Preprocess(const ToolChain &TC) : Common("gcc::Preprocess", TC) {} + Preprocess(const ToolChain &TC) : Common("gcc::Preprocess", + "gcc preprocessor", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -87,9 +110,10 @@ namespace gcc { ArgStringList &CmdArgs) const; }; - class VISIBILITY_HIDDEN Precompile : public Common { + class LLVM_LIBRARY_VISIBILITY Precompile : public Common { public: - Precompile(const ToolChain &TC) : Common("gcc::Precompile", TC) {} + Precompile(const ToolChain &TC) : Common("gcc::Precompile", + "gcc precompile", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return false; } @@ -100,9 +124,10 @@ namespace gcc { ArgStringList &CmdArgs) const; }; - class VISIBILITY_HIDDEN Compile : public Common { + class LLVM_LIBRARY_VISIBILITY Compile : public Common { public: - Compile(const ToolChain &TC) : Common("gcc::Compile", TC) {} + Compile(const ToolChain &TC) : Common("gcc::Compile", + "gcc frontend", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -113,9 +138,10 @@ namespace gcc { ArgStringList &CmdArgs) const; }; - class VISIBILITY_HIDDEN Assemble : public Common { + class LLVM_LIBRARY_VISIBILITY Assemble : public Common { public: - Assemble(const ToolChain &TC) : Common("gcc::Assemble", TC) {} + Assemble(const ToolChain &TC) : Common("gcc::Assemble", + "assembler (via gcc)", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return false; } @@ -125,9 +151,10 @@ namespace gcc { ArgStringList &CmdArgs) const; }; - class VISIBILITY_HIDDEN Link : public Common { + class LLVM_LIBRARY_VISIBILITY Link : public Common { public: - Link(const ToolChain &TC) : Common("gcc::Link", TC) {} + Link(const ToolChain &TC) : Common("gcc::Link", + "linker (via gcc)", TC) {} virtual bool acceptsPipedInput() const { return false; } virtual bool canPipeOutput() const { return false; } @@ -139,7 +166,7 @@ namespace gcc { } // end namespace gcc namespace darwin { - class VISIBILITY_HIDDEN DarwinTool : public Tool { + class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool { protected: void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const; @@ -148,10 +175,11 @@ namespace darwin { } public: - DarwinTool(const char *Name, const ToolChain &TC) : Tool(Name, TC) {} + DarwinTool(const char *Name, const char *ShortName, + const ToolChain &TC) : Tool(Name, ShortName, TC) {} }; - class VISIBILITY_HIDDEN CC1 : public DarwinTool { + class LLVM_LIBRARY_VISIBILITY CC1 : public DarwinTool { public: static const char *getBaseInputName(const ArgList &Args, const InputInfoList &Input); @@ -176,7 +204,8 @@ namespace darwin { void AddCPPArgs(const ArgList &Args, ArgStringList &CmdArgs) const; public: - CC1(const char *Name, const ToolChain &TC) : DarwinTool(Name, TC) {} + CC1(const char *Name, const char *ShortName, + const ToolChain &TC) : DarwinTool(Name, ShortName, TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -184,9 +213,10 @@ namespace darwin { virtual bool hasIntegratedCPP() const { return true; } }; - class VISIBILITY_HIDDEN Preprocess : public CC1 { + class LLVM_LIBRARY_VISIBILITY Preprocess : public CC1 { public: - Preprocess(const ToolChain &TC) : CC1("darwin::Preprocess", TC) {} + Preprocess(const ToolChain &TC) : CC1("darwin::Preprocess", + "gcc preprocessor", TC) {} virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, @@ -196,9 +226,9 @@ namespace darwin { const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Compile : public CC1 { + class LLVM_LIBRARY_VISIBILITY Compile : public CC1 { public: - Compile(const ToolChain &TC) : CC1("darwin::Compile", TC) {} + Compile(const ToolChain &TC) : CC1("darwin::Compile", "gcc frontend", TC) {} virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, @@ -208,9 +238,10 @@ namespace darwin { const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Assemble : public DarwinTool { + class LLVM_LIBRARY_VISIBILITY Assemble : public DarwinTool { public: - Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble", TC) {} + Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble", + "assembler", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return false; } @@ -224,11 +255,11 @@ namespace darwin { const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Link : public DarwinTool { + class LLVM_LIBRARY_VISIBILITY Link : public DarwinTool { void AddLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const; public: - Link(const ToolChain &TC) : DarwinTool("darwin::Link", TC) {} + Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {} virtual bool acceptsPipedInput() const { return false; } virtual bool canPipeOutput() const { return false; } @@ -242,9 +273,9 @@ namespace darwin { const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Lipo : public DarwinTool { + class LLVM_LIBRARY_VISIBILITY Lipo : public DarwinTool { public: - Lipo(const ToolChain &TC) : DarwinTool("darwin::Lipo", TC) {} + Lipo(const ToolChain &TC) : DarwinTool("darwin::Lipo", "lipo", TC) {} virtual bool acceptsPipedInput() const { return false; } virtual bool canPipeOutput() const { return false; } @@ -261,9 +292,10 @@ namespace darwin { /// openbsd -- Directly call GNU Binutils assembler and linker namespace openbsd { - class VISIBILITY_HIDDEN Assemble : public Tool { + class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { public: - Assemble(const ToolChain &TC) : Tool("openbsd::Assemble", TC) {} + Assemble(const ToolChain &TC) : Tool("openbsd::Assemble", "assembler", + TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -276,9 +308,9 @@ namespace openbsd { const ArgList &TCArgs, const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Link : public Tool { + class LLVM_LIBRARY_VISIBILITY Link : public Tool { public: - Link(const ToolChain &TC) : Tool("openbsd::Link", TC) {} + Link(const ToolChain &TC) : Tool("openbsd::Link", "linker", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -295,9 +327,10 @@ namespace openbsd { /// freebsd -- Directly call GNU Binutils assembler and linker namespace freebsd { - class VISIBILITY_HIDDEN Assemble : public Tool { + class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { public: - Assemble(const ToolChain &TC) : Tool("freebsd::Assemble", TC) {} + Assemble(const ToolChain &TC) : Tool("freebsd::Assemble", "assembler", + TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -310,9 +343,9 @@ namespace freebsd { const ArgList &TCArgs, const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Link : public Tool { + class LLVM_LIBRARY_VISIBILITY Link : public Tool { public: - Link(const ToolChain &TC) : Tool("freebsd::Link", TC) {} + Link(const ToolChain &TC) : Tool("freebsd::Link", "linker", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -329,9 +362,10 @@ namespace freebsd { /// auroraux -- Directly call GNU Binutils assembler and linker namespace auroraux { - class VISIBILITY_HIDDEN Assemble : public Tool { + class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { public: - Assemble(const ToolChain &TC) : Tool("auroraux::Assemble", TC) {} + Assemble(const ToolChain &TC) : Tool("auroraux::Assemble", "assembler", + TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -344,9 +378,9 @@ namespace auroraux { const ArgList &TCArgs, const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Link : public Tool { + class LLVM_LIBRARY_VISIBILITY Link : public Tool { public: - Link(const ToolChain &TC) : Tool("auroraux::Link", TC) {} + Link(const ToolChain &TC) : Tool("auroraux::Link", "linker", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -363,9 +397,10 @@ namespace auroraux { /// dragonfly -- Directly call GNU Binutils assembler and linker namespace dragonfly { - class VISIBILITY_HIDDEN Assemble : public Tool { + class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { public: - Assemble(const ToolChain &TC) : Tool("dragonfly::Assemble", TC) {} + Assemble(const ToolChain &TC) : Tool("dragonfly::Assemble", "assembler", + TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -378,9 +413,9 @@ namespace dragonfly { const ArgList &TCArgs, const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Link : public Tool { + class LLVM_LIBRARY_VISIBILITY Link : public Tool { public: - Link(const ToolChain &TC) : Tool("dragonfly::Link", TC) {} + Link(const ToolChain &TC) : Tool("dragonfly::Link", "linker", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 87c3fca24962..6a4727929e7a 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -174,10 +174,10 @@ public: Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), PP.getLangOptions(), PD, CreateStoreMgr, CreateConstraintMgr, - Opts.MaxNodes, + Opts.MaxNodes, Opts.MaxLoop, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, Opts.PurgeDead, Opts.EagerlyAssume, - Opts.TrimGraph)); + Opts.TrimGraph, Opts.InlineCall)); } virtual void HandleTranslationUnit(ASTContext &C); diff --git a/lib/Frontend/BoostConAction.cpp b/lib/Frontend/BoostConAction.cpp new file mode 100644 index 000000000000..ae150c6ec21e --- /dev/null +++ b/lib/Frontend/BoostConAction.cpp @@ -0,0 +1,39 @@ +//===-- BoostConAction.cpp - BoostCon Workshop Action -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "clang/Frontend/FrontendActions.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include <cstdio> +#include <iostream> +using namespace clang; + +namespace { + class BoostConASTConsumer : public ASTConsumer, + public RecursiveASTVisitor<BoostConASTConsumer> { + public: + /// HandleTranslationUnit - This method is called when the ASTs for entire + /// translation unit have been parsed. + virtual void HandleTranslationUnit(ASTContext &Ctx); + + bool VisitCXXRecordDecl(CXXRecordDecl *D) { + std::cout << D->getNameAsString() << std::endl; + return false; + } + }; +} + +ASTConsumer *BoostConAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new BoostConASTConsumer(); +} + +void BoostConASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { + fprintf(stderr, "Welcome to BoostCon!\n"); + Visit(Ctx.getTranslationUnitDecl()); +} diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index b69ad9740d2a..01592d1f81e4 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(clangFrontend ASTMerge.cpp ASTUnit.cpp AnalysisConsumer.cpp + BoostConAction.cpp CacheTokens.cpp CodeGenAction.cpp CompilerInstance.cpp @@ -54,4 +55,5 @@ ENDIF(MSVC) add_dependencies(clangFrontend ClangDiagnosticFrontend ClangDiagnosticLex - ClangDiagnosticSema) + ClangDiagnosticSema + ClangStmtNodes) diff --git a/lib/Frontend/CodeGenAction.cpp b/lib/Frontend/CodeGenAction.cpp index 79d7d5f4c241..3416aa825fcb 100644 --- a/lib/Frontend/CodeGenAction.cpp +++ b/lib/Frontend/CodeGenAction.cpp @@ -48,6 +48,7 @@ namespace { Backend_EmitBC, ///< Emit LLVM bitcode files Backend_EmitLL, ///< Emit human-readable LLVM assembly Backend_EmitNothing, ///< Don't emit anything (benchmarking mode) + Backend_EmitMCNull, ///< Run CodeGen, but don't emit anything Backend_EmitObj ///< Emit native object files }; @@ -180,6 +181,10 @@ namespace { Gen->CompleteTentativeDefinition(D); } + virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) { + Gen->HandleVTable(RD, DefinitionRequired); + } + static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context, unsigned LocCookie) { SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie); @@ -316,6 +321,9 @@ bool BackendConsumer::AddEmitPasses() { } TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr); + if (CodeGenOpts.RelaxAll) + TM->setMCRelaxAll(true); + // Set register scheduler & allocation policy. RegisterScheduler::setDefault(createDefaultScheduler); RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator : @@ -336,6 +344,10 @@ bool BackendConsumer::AddEmitPasses() { TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile; if (Action == Backend_EmitObj) CGFT = TargetMachine::CGFT_ObjectFile; + else if (Action == Backend_EmitMCNull) + CGFT = TargetMachine::CGFT_Null; + else + assert(Action == Backend_EmitAssembly && "Invalid action!"); if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel, /*DisableVerify=*/!CodeGenOpts.VerifyModule)) { Diags.Report(diag::err_fe_unable_to_interface_with_target); @@ -553,6 +565,7 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, break; case Backend_EmitNothing: break; + case Backend_EmitMCNull: case Backend_EmitObj: OS.reset(CI.createDefaultOutputFile(true, InFile, "o")); break; @@ -575,4 +588,6 @@ EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} +EmitCodeGenOnlyAction::EmitCodeGenOnlyAction() : CodeGenAction(Backend_EmitMCNull) {} + EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {} diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 5ed9c409a3dc..2b251682b713 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -295,6 +295,7 @@ void CompilerInstance::createCodeCompletionConsumer() { Loc.FileName, Loc.Line, Loc.Column, getFrontendOpts().DebugCodeCompletionPrinter, getFrontendOpts().ShowMacrosInCodeCompletion, + getFrontendOpts().ShowCodePatternsInCodeCompletion, llvm::outs())); if (!CompletionConsumer) return; @@ -317,6 +318,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, unsigned Column, bool UseDebugPrinter, bool ShowMacros, + bool ShowCodePatterns, llvm::raw_ostream &OS) { // Tell the source manager to chop off the given file at a specific // line and column. @@ -332,9 +334,9 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, // Set up the creation routine for code-completion. if (UseDebugPrinter) - return new PrintingCodeCompleteConsumer(ShowMacros, OS); + return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS); else - return new CIndexCodeCompleteConsumer(ShowMacros, OS); + return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS); } // Output Files diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 729c1dcc15e1..1d81e82ca37b 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -187,6 +187,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-fobjc-dispatch-method=non-legacy"); break; } + if (Opts.RelaxAll) + Res.push_back("-mrelax-all"); if (Opts.SoftFloat) Res.push_back("-msoft-float"); if (Opts.UnwindTables) @@ -243,6 +245,10 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-fdiagnostics-binary"); if (Opts.ShowOptionNames) Res.push_back("-fdiagnostics-show-option"); + if (Opts.ShowCategories == 1) + Res.push_back("-fdiagnostics-show-category=id"); + else if (Opts.ShowCategories == 2) + Res.push_back("-fdiagnostics-show-category=name"); if (Opts.ErrorLimit) { Res.push_back("-ferror-limit"); Res.push_back(llvm::utostr(Opts.ErrorLimit)); @@ -304,6 +310,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::ASTPrint: return "-ast-print"; case frontend::ASTPrintXML: return "-ast-print-xml"; case frontend::ASTView: return "-ast-view"; + case frontend::BoostCon: return "-boostcon"; case frontend::DumpRawTokens: return "-dump-raw-tokens"; case frontend::DumpTokens: return "-dump-tokens"; case frontend::EmitAssembly: return "-S"; @@ -311,6 +318,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::EmitHTML: return "-emit-html"; case frontend::EmitLLVM: return "-emit-llvm"; case frontend::EmitLLVMOnly: return "-emit-llvm-only"; + case frontend::EmitCodeGenOnly: return "-emit-codegen-only"; case frontend::EmitObj: return "-emit-obj"; case frontend::FixIt: return "-fixit"; case frontend::GeneratePCH: return "-emit-pch"; @@ -344,6 +352,8 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-help"); if (Opts.ShowMacrosInCodeCompletion) Res.push_back("-code-completion-macros"); + if (Opts.ShowCodePatternsInCodeCompletion) + Res.push_back("-code-completion-patterns"); if (Opts.ShowStats) Res.push_back("-print-stats"); if (Opts.ShowTimers) @@ -695,34 +705,6 @@ void CompilerInvocation::toArgs(std::vector<std::string> &Res) { using namespace clang::driver; using namespace clang::driver::cc1options; -static llvm::StringRef getLastArgValue(ArgList &Args, cc1options::ID ID, - llvm::StringRef Default = "") { - if (Arg *A = Args.getLastArg(ID)) - return A->getValue(Args); - return Default; -} - -static int getLastArgIntValue(ArgList &Args, cc1options::ID ID, - int Default, Diagnostic &Diags) { - Arg *A = Args.getLastArg(ID); - if (!A) - return Default; - - int Res = Default; - if (llvm::StringRef(A->getValue(Args)).getAsInteger(10, Res)) - Diags.Report(diag::err_drv_invalid_int_value) - << A->getAsString(Args) << A->getValue(Args); - - return Res; -} - -static std::vector<std::string> -getAllArgValues(ArgList &Args, cc1options::ID ID) { - llvm::SmallVector<const char *, 16> Values; - Args.AddAllArgValues(Values, ID); - return std::vector<std::string>(Values.begin(), Values.end()); -} - // static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, @@ -787,12 +769,14 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); - Opts.AnalyzeSpecificFunction = getLastArgValue(Args, OPT_analyze_function); + Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks); Opts.EnableExperimentalInternalChecks = Args.hasArg(OPT_analyzer_experimental_internal_checks); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); - Opts.MaxNodes = getLastArgIntValue(Args, OPT_analyzer_max_nodes,150000,Diags); + Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); + Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 3, Diags); + Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call); } static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, @@ -802,7 +786,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_Os)) Opts.OptimizationLevel = 2; else { - Opts.OptimizationLevel = getLastArgIntValue(Args, OPT_O, 0, Diags); + Opts.OptimizationLevel = Args.getLastArgIntValue(OPT_O, 0, Diags); if (Opts.OptimizationLevel > 3) { Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel; @@ -817,7 +801,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.DebugInfo = Args.hasArg(OPT_g); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); - Opts.DwarfDebugFlags = getLastArgValue(Args, OPT_dwarf_debug_flags); + Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); @@ -827,20 +811,21 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); - Opts.CodeModel = getLastArgValue(Args, OPT_mcode_model); - Opts.DebugPass = getLastArgValue(Args, OPT_mdebug_pass); + Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model); + Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass); Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim); - Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi); - Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision); + Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi); + Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision); Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); + Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.SoftFloat = Args.hasArg(OPT_msoft_float); Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); - Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic"); + Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections); Opts.DataSections = Args.hasArg(OPT_fdata_sections); - Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name); + Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { @@ -860,8 +845,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, ArgList &Args) { using namespace cc1options; - Opts.OutputFile = getLastArgValue(Args, OPT_dependency_file); - Opts.Targets = getAllArgValues(Args, OPT_MT); + Opts.OutputFile = Args.getLastArgValue(OPT_dependency_file); + Opts.Targets = Args.getAllArgValues(OPT_MT); Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps); Opts.UsePhonyTargets = Args.hasArg(OPT_MP); } @@ -879,27 +864,41 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option); + + llvm::StringRef ShowCategory = + Args.getLastArgValue(OPT_fdiagnostics_show_category, "none"); + if (ShowCategory == "none") + Opts.ShowCategories = 0; + else if (ShowCategory == "id") + Opts.ShowCategories = 1; + else if (ShowCategory == "name") + Opts.ShowCategories = 2; + else + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) + << ShowCategory; + Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary); - Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags); + Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags); Opts.MacroBacktraceLimit - = getLastArgIntValue(Args, OPT_fmacro_backtrace_limit, + = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit, DiagnosticOptions::DefaultMacroBacktraceLimit, Diags); Opts.TemplateBacktraceLimit - = getLastArgIntValue(Args, OPT_ftemplate_backtrace_limit, + = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit, DiagnosticOptions::DefaultTemplateBacktraceLimit, Diags); - Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop, + Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop, DiagnosticOptions::DefaultTabStop, Diags); if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { Diags.Report(diag::warn_ignoring_ftabstop_value) << Opts.TabStop << DiagnosticOptions::DefaultTabStop; Opts.TabStop = DiagnosticOptions::DefaultTabStop; } - Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags); - Opts.DumpBuildInformation = getLastArgValue(Args, OPT_dump_build_information); - Opts.Warnings = getAllArgValues(Args, OPT_W); + Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags); + Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information); + Opts.Warnings = Args.getAllArgValues(OPT_W); } static FrontendOptions::InputKind @@ -918,6 +917,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ProgramAction = frontend::ASTPrintXML; break; case OPT_ast_view: Opts.ProgramAction = frontend::ASTView; break; + case OPT_boostcon: + Opts.ProgramAction = frontend::BoostCon; break; case OPT_dump_raw_tokens: Opts.ProgramAction = frontend::DumpRawTokens; break; case OPT_dump_tokens: @@ -932,6 +933,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ProgramAction = frontend::EmitLLVM; break; case OPT_emit_llvm_only: Opts.ProgramAction = frontend::EmitLLVMOnly; break; + case OPT_emit_codegen_only: + Opts.ProgramAction = frontend::EmitCodeGenOnly; break; case OPT_emit_obj: Opts.ProgramAction = frontend::EmitObj; break; case OPT_fixit_EQ: @@ -983,17 +986,19 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { !Args.hasArg(OPT_no_code_completion_debug_printer); Opts.DisableFree = Args.hasArg(OPT_disable_free); - Opts.OutputFile = getLastArgValue(Args, OPT_o); - Opts.Plugins = getAllArgValues(Args, OPT_load); + Opts.OutputFile = Args.getLastArgValue(OPT_o); + Opts.Plugins = Args.getAllArgValues(OPT_load); Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); Opts.ShowHelp = Args.hasArg(OPT_help); Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); + Opts.ShowCodePatternsInCodeCompletion + = Args.hasArg(OPT_code_completion_patterns); Opts.ShowStats = Args.hasArg(OPT_print_stats); Opts.ShowTimers = Args.hasArg(OPT_ftime_report); Opts.ShowVersion = Args.hasArg(OPT_version); - Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view); - Opts.ASTMergeFiles = getAllArgValues(Args, OPT_ast_merge); - Opts.LLVMArgs = getAllArgValues(Args, OPT_mllvm); + Opts.ViewClassInheritance = Args.getLastArgValue(OPT_cxx_inheritance_view); + Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge); + Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); FrontendOptions::InputKind DashX = FrontendOptions::IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { @@ -1022,7 +1027,7 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { } // '-' is the default input if none is given. - std::vector<std::string> Inputs = getAllArgValues(Args, OPT_INPUT); + std::vector<std::string> Inputs = Args.getAllArgValues(OPT_INPUT); Opts.Inputs.clear(); if (Inputs.empty()) Inputs.push_back("-"); @@ -1060,12 +1065,12 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0, static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { using namespace cc1options; - Opts.Sysroot = getLastArgValue(Args, OPT_isysroot, "/"); + Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx); - Opts.ResourceDir = getLastArgValue(Args, OPT_resource_dir); + Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); // Add -I... and -F... options in order. for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), @@ -1204,8 +1209,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_pthread)) Opts.POSIXThreads = 1; - llvm::StringRef Vis = getLastArgValue(Args, OPT_fvisibility, - "default"); + llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); if (Vis == "default") Opts.setVisibilityMode(LangOptions::Default); else if (Vis == "hidden") @@ -1247,18 +1251,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); Opts.MathErrno = Args.hasArg(OPT_fmath_errno); - Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 1024, + Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024, Diags); Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); - Opts.ObjCConstantStringClass = getLastArgValue(Args, - OPT_fconstant_string_class); + Opts.ObjCConstantStringClass = + Args.getLastArgValue(OPT_fconstant_string_class); Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); Opts.ObjCNonFragileABI2 = Args.hasArg(OPT_fobjc_nonfragile_abi2); if (Opts.ObjCNonFragileABI2) Opts.ObjCNonFragileABI = true; Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); - Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); + Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags); Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions); Opts.Static = Args.hasArg(OPT_static_define); Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts); @@ -1268,7 +1272,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, // FIXME: Eliminate this dependency. unsigned Opt = - Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags); + Args.hasArg(OPT_Os) ? 2 : Args.getLastArgIntValue(OPT_O, 0, Diags); Opts.Optimize = Opt != 0; // This is the __NO_INLINE__ define, which just depends on things like the @@ -1278,7 +1282,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, // FIXME: This is affected by other options (-fno-inline). Opts.NoInline = !Opt; - unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags); + unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags); switch (SSP) { default: Diags.Report(diag::err_drv_invalid_value) @@ -1293,8 +1297,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Diagnostic &Diags) { using namespace cc1options; - Opts.ImplicitPCHInclude = getLastArgValue(Args, OPT_include_pch); - Opts.ImplicitPTHInclude = getLastArgValue(Args, OPT_include_pth); + Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); + Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); if (const Arg *A = Args.getLastArg(OPT_token_cache)) Opts.TokenCache = A->getValue(Args); else @@ -1310,7 +1314,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.addMacroUndef(it->getValue(Args)); } - Opts.MacroIncludes = getAllArgValues(Args, OPT_imacros); + Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros); // Add the ordered list of -includes. for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch, @@ -1358,10 +1362,10 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { using namespace cc1options; - Opts.ABI = getLastArgValue(Args, OPT_target_abi); - Opts.CPU = getLastArgValue(Args, OPT_target_cpu); - Opts.Triple = getLastArgValue(Args, OPT_triple); - Opts.Features = getAllArgValues(Args, OPT_target_feature); + Opts.ABI = Args.getLastArgValue(OPT_target_abi); + Opts.CPU = Args.getLastArgValue(OPT_target_cpu); + Opts.Triple = Args.getLastArgValue(OPT_triple); + Opts.Features = Args.getAllArgValues(OPT_target_feature); // Use the host triple if unspecified. if (Opts.Triple.empty()) diff --git a/lib/Frontend/DeclXML.cpp b/lib/Frontend/DeclXML.cpp index 8750b1efcab5..97a7f5558392 100644 --- a/lib/Frontend/DeclXML.cpp +++ b/lib/Frontend/DeclXML.cpp @@ -47,11 +47,39 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> { void addSubNodes(CXXRecordDecl* RD) { addSubNodes(cast<RecordDecl>(RD)); - for (CXXRecordDecl::method_iterator i = RD->method_begin(), - e = RD->method_end(); i != e; ++i) { - Visit(*i); - Doc.toParent(); + + if (RD->isDefinition()) { + // FIXME: This breaks XML generation + //Doc.addAttribute("num_bases", RD->getNumBases()); + + for (CXXRecordDecl::base_class_iterator + base = RD->bases_begin(), + bend = RD->bases_end(); + base != bend; + ++base) { + Doc.addSubNode("Base"); + Doc.addAttribute("id", base->getType()); + AccessSpecifier as = base->getAccessSpecifierAsWritten(); + const char* as_name = ""; + switch(as) { + case AS_none: as_name = ""; break; + case AS_public: as_name = "public"; break; + case AS_protected: as_name = "protected"; break; + case AS_private: as_name = "private"; break; + } + Doc.addAttributeOptional("access", as_name); + Doc.addAttribute("is_virtual", base->isVirtual()); + Doc.toParent(); + } + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + Visit(*i); + Doc.toParent(); + } + } + } void addSubNodes(EnumDecl* ED) { @@ -82,6 +110,18 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> { Doc.PrintStmt(argDecl->getDefaultArg()); } + void addSubNodes(NamespaceDecl* ns) { + + for (DeclContext::decl_iterator + d = ns->decls_begin(), + dend = ns->decls_end(); + d != dend; + ++d) { + Visit(*d); + Doc.toParent(); + } + } + void addSpecialAttribute(const char* pName, EnumDecl* ED) { const QualType& enumType = ED->getIntegerType(); if (!enumType.isNull()) diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp index 0263c30bfd57..894f230216f6 100644 --- a/lib/Frontend/DocumentXML.cpp +++ b/lib/Frontend/DocumentXML.cpp @@ -199,6 +199,35 @@ void DocumentXML::addPtrAttribute(const char* pAttributeName, } //--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pAttributeName, + const NestedNameSpecifier* pNNS) { + switch (pNNS->getKind()) { + case NestedNameSpecifier::Identifier: { + IdentifierInfo *ii = pNNS->getAsIdentifier(); + // FIXME how should we handle those ? + addPtrAttribute(pAttributeName, ii->getName().data()); + break; + } + case NestedNameSpecifier::Namespace: { + addPtrAttribute(pAttributeName, pNNS->getAsNamespace()); + break; + } + case NestedNameSpecifier::TypeSpec: { + addPtrAttribute(pAttributeName, pNNS->getAsType()); + break; + } + case NestedNameSpecifier::TypeSpecWithTemplate: { + addPtrAttribute(pAttributeName, pNNS->getAsType()); + break; + } + case NestedNameSpecifier::Global: { + addPtrAttribute(pAttributeName, "::"); + break; + } + } +} + +//--------------------------------------------------------- void DocumentXML::addTypeRecursively(const QualType& pType) { if (addToMap(Types, pType)) diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 12a4d4dbd094..e0391c254b38 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -54,7 +54,7 @@ public: bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot = false); - /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to suport a gnu + /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu /// libstdc++. void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, llvm::StringRef ArchDir, @@ -73,7 +73,8 @@ public: void AddDelimitedPaths(llvm::StringRef String); // AddDefaultCIncludePaths - Add paths that should always be searched. - void AddDefaultCIncludePaths(const llvm::Triple &triple); + void AddDefaultCIncludePaths(const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts); // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when // compiling c++. @@ -83,7 +84,7 @@ public: /// that e.g. stdio.h is found. void AddDefaultSystemIncludePaths(const LangOptions &Lang, const llvm::Triple &triple, - bool UseStandardCXXIncludes); + const HeaderSearchOptions &HSOpts); /// Realize - Merges all search path lists into one list and send it to /// HeaderSearch. @@ -323,10 +324,14 @@ static bool getSystemRegistryString(const char*, const char*, char*, size_t) { // Get Visual Studio installation directory. static bool getVisualStudioDir(std::string &path) { char vsIDEInstallDir[256]; + char vsExpressIDEInstallDir[256]; // Try the Windows registry first. bool hasVCDir = getSystemRegistryString( "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION", "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1); + bool hasVCExpressDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION", + "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1); // If we have both vc80 and vc90, pick version we were compiled with. if (hasVCDir && vsIDEInstallDir[0]) { char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE"); @@ -335,25 +340,43 @@ static bool getVisualStudioDir(std::string &path) { path = vsIDEInstallDir; return(true); } + else if (hasVCExpressDir && vsExpressIDEInstallDir[0]) { + char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE"); + if (p) + *p = '\0'; + path = vsExpressIDEInstallDir; + return(true); + } else { // Try the environment. + const char* vs100comntools = getenv("VS100COMNTOOLS"); const char* vs90comntools = getenv("VS90COMNTOOLS"); const char* vs80comntools = getenv("VS80COMNTOOLS"); const char* vscomntools = NULL; - // If we have both vc80 and vc90, pick version we were compiled with. - if (vs90comntools && vs80comntools) { - #if (_MSC_VER >= 1500) // VC90 - vscomntools = vs90comntools; - #elif (_MSC_VER == 1400) // VC80 - vscomntools = vs80comntools; - #else - vscomntools = vs90comntools; - #endif + + // Try to find the version that we were compiled with + if(false) {} + #if (_MSC_VER >= 1600) // VC100 + else if(vs100comntools) { + vscomntools = vs100comntools; } + #elif (_MSC_VER == 1500) // VC80 + else if(vs90comntools) { + vscomntools = vs90comntools; + } + #elif (_MSC_VER == 1400) // VC80 + else if(vs80comntools) { + vscomntools = vs80comntools; + } + #endif + // Otherwise find any version we can + else if (vs100comntools) + vscomntools = vs100comntools; else if (vs90comntools) vscomntools = vs90comntools; else if (vs80comntools) vscomntools = vs80comntools; + if (vscomntools && *vscomntools) { char *p = const_cast<char *>(strstr(vscomntools, "\\Common7\\Tools")); if (p) @@ -382,8 +405,22 @@ static bool getWindowsSDKDir(std::string &path) { return(false); } -void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { +void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts) { // FIXME: temporary hack: hard-coded paths. + AddPath("/usr/local/include", System, true, false, false); + + // Builtin includes use #include_next directives and should be positioned + // just prior C include dirs. + if (HSOpts.UseBuiltinIncludes) { + // Ignore the sys root, we *always* look for clang headers relative to + // supplied path. + llvm::sys::Path P(HSOpts.ResourceDir); + P.appendComponent("include"); + AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); + } + + // Add dirs specified via 'configure --with-c-include-dirs'. llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS); if (CIncludeDirs != "") { llvm::SmallVector<llvm::StringRef, 5> dirs; @@ -410,6 +447,8 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { } else { // Default install paths. + AddPath("C:/Program Files/Microsoft Visual Studio 10.0/VC/include", + System, false, false, false); AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include", System, false, false, false); AddPath( @@ -480,21 +519,23 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { break; } - AddPath("/usr/local/include", System, true, false, false); AddPath("/usr/include", System, false, false, false); } -void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { +void InitHeaderSearch:: +AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { llvm::Triple::OSType os = triple.getOS(); llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); if (CxxIncludeRoot != "") { llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); if (CxxIncludeArch == "") AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(), - CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple); + CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, + triple); else AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, CXX_INCLUDE_ARCH, - CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple); + CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, + triple); return; } // FIXME: temporary hack: hard-coded paths. @@ -527,62 +568,78 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddPath("/usr/include/c++/4.1", System, true, false, false); break; case llvm::Triple::Linux: - // Exherbo (2010-01-25) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", - "x86_64-pc-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", - "i686-pc-linux-gnu", "", "", triple); - // Debian sid + //===------------------------------------------------------------------===// + // Debian based distros. + // Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y + //===------------------------------------------------------------------===// + // Ubuntu 10.04 LTS "Lucid Lynx" -- gcc-4.4.3 + // Ubuntu 9.10 "Karmic Koala" -- gcc-4.4.1 + // Debian 6.0 "squeeze" -- gcc-4.4.2 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", "x86_64-linux-gnu", "32", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "i486-linux-gnu", "64", "", triple); - // Ubuntu 7.10 - Gutsy Gibbon - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3", - "i486-linux-gnu", "", "", triple); - // Ubuntu 9.04 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3", - "x86_64-linux-gnu","32", "", triple); - // Ubuntu 9.10 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", + "i486-linux-gnu", "", "64", triple); + // Ubuntu 9.04 "Jaunty Jackalope" -- gcc-4.3.3 + // Ubuntu 8.10 "Intrepid Ibex" -- gcc-4.3.2 + // Debian 5.0 "lenny" -- gcc-4.3.2 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", "x86_64-linux-gnu", "32", "", triple); - // Fedora 8 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", - "i386-redhat-linux", "", "", triple); - // Fedora 9 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", - "i386-redhat-linux", "", "", triple); - // Fedora 10 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", - "i386-redhat-linux","", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i486-linux-gnu", "", "64", triple); + // Ubuntu 8.04.4 LTS "Hardy Heron" -- gcc-4.2.4 + // Ubuntu 8.04.[0-3] LTS "Hardy Heron" -- gcc-4.2.3 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", + "x86_64-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", + "i486-linux-gnu", "", "64", triple); + // Ubuntu 7.10 "Gutsy Gibbon" -- gcc-4.1.3 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1", + "x86_64-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1", + "i486-linux-gnu", "", "64", triple); - // Fedora 10 x86_64 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", + //===------------------------------------------------------------------===// + // Redhat based distros. + //===------------------------------------------------------------------===// + // Fedora 13 + // Fedora 12 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", "x86_64-redhat-linux", "32", "", triple); - + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", + "i686-redhat-linux","", "", triple); + // Fedora 12 (pre-FEB-2010) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "i686-redhat-linux","", "", triple); // Fedora 11 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", - "i586-redhat-linux","", "", triple); - - // Fedora 11 x86_64 + "x86_64-redhat-linux", "32", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", + "i586-redhat-linux","", "", triple); + // Fedora 10 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", "x86_64-redhat-linux", "32", "", triple); - - // Fedora 12 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", - "i686-redhat-linux","", "", triple); - - // Fedora 12 x86_64 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", + "i386-redhat-linux","", "", triple); + // Fedora 9 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", + "i386-redhat-linux", "", "", triple); + // Fedora 8 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", + "x86_64-redhat-linux", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", + "i386-redhat-linux", "", "", triple); - // Fedora 12 (February-2010+) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", - "i686-redhat-linux","", "", triple); + //===------------------------------------------------------------------===// - // Fedora 12 (February-2010+) x86_64 + // Exherbo (2010-01-25) AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", - "x86_64-redhat-linux", "32", "", triple); + "x86_64-pc-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", + "i686-pc-linux-gnu", "", "", triple); // openSUSE 11.1 32 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", @@ -612,12 +669,6 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", "i686-pc-linux-gnu", "", "", triple); - // Ubuntu 8.10 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-pc-linux-gnu", "", "", triple); - // Ubuntu 9.04 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-linux-gnu","", "", triple); // Gentoo amd64 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", @@ -635,6 +686,8 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl break; case llvm::Triple::FreeBSD: + // FreeBSD 8.0 + // FreeBSD 7.3 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple); break; case llvm::Triple::Solaris: @@ -651,11 +704,11 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, const llvm::Triple &triple, - bool UseStandardCXXIncludes) { - if (Lang.CPlusPlus && UseStandardCXXIncludes) + const HeaderSearchOptions &HSOpts) { + if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) AddDefaultCPlusPlusIncludePaths(triple); - AddDefaultCIncludePaths(triple); + AddDefaultCIncludePaths(triple, HSOpts); // Add the default framework include paths on Darwin. if (triple.getOS() == llvm::Triple::Darwin) { @@ -813,17 +866,8 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, else Init.AddDelimitedPaths(HSOpts.CEnvIncPath); - if (HSOpts.UseBuiltinIncludes) { - // Ignore the sys root, we *always* look for clang headers relative to - // supplied path. - llvm::sys::Path P(HSOpts.ResourceDir); - P.appendComponent("include"); - Init.AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); - } - if (HSOpts.UseStandardIncludes) - Init.AddDefaultSystemIncludePaths(Lang, Triple, - HSOpts.UseStandardCXXIncludes); + Init.AddDefaultSystemIncludePaths(Lang, Triple, HSOpts); Init.Realize(); } diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index f1e9819d83ca..2b35c8e2296b 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -428,6 +428,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (FEOpts.ProgramAction == frontend::RewriteObjC) Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); + + // Define a macro that exists only when using the static analyzer. + if (FEOpts.ProgramAction == frontend::RunAnalysis) + Builder.defineMacro("__clang_analyzer__"); + // Get other target #defines. TI.getTargetDefines(LangOpts, Builder); } diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index ae57ce581def..88e9b9db1805 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -2165,28 +2165,32 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return QualType(); } unsigned Tag = Record[1]; - return Context->getElaboratedType(GetType(Record[0]), - (ElaboratedType::TagKind) Tag); + // FIXME: Deserialize the qualifier (C++ only) + return Context->getElaboratedType((ElaboratedTypeKeyword) Tag, + /* NNS */ 0, + GetType(Record[0])); } case pch::TYPE_OBJC_INTERFACE: { unsigned Idx = 0; ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(Record[Idx++])); + return Context->getObjCInterfaceType(ItfD); + } + + case pch::TYPE_OBJC_OBJECT: { + unsigned Idx = 0; + QualType Base = GetType(Record[Idx++]); unsigned NumProtos = Record[Idx++]; llvm::SmallVector<ObjCProtocolDecl*, 4> Protos; for (unsigned I = 0; I != NumProtos; ++I) Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++]))); - return Context->getObjCInterfaceType(ItfD, Protos.data(), NumProtos); + return Context->getObjCObjectType(Base, Protos.data(), NumProtos); } case pch::TYPE_OBJC_OBJECT_POINTER: { unsigned Idx = 0; - QualType OIT = GetType(Record[Idx++]); - unsigned NumProtos = Record[Idx++]; - llvm::SmallVector<ObjCProtocolDecl*, 4> Protos; - for (unsigned I = 0; I != NumProtos; ++I) - Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++]))); - return Context->getObjCObjectPointerType(OIT, Protos.data(), NumProtos); + QualType Pointee = GetType(Record[Idx++]); + return Context->getObjCObjectPointerType(Pointee); } case pch::TYPE_SUBST_TEMPLATE_TYPE_PARM: { @@ -2334,9 +2338,6 @@ void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } -void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } @@ -2354,17 +2355,23 @@ void TypeLocReader::VisitTemplateSpecializationTypeLoc( Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(i).getKind(), Record, Idx)); } -void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx)); } void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx)); TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + TL.setHasBaseTypeAsWritten(Record[Idx++]); TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) @@ -2372,13 +2379,6 @@ void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setHasBaseTypeAsWritten(Record[Idx++]); - TL.setHasProtocolsAsWritten(Record[Idx++]); - if (TL.hasProtocolsAsWritten()) - for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) - TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); } TypeSourceInfo *PCHReader::GetTypeSourceInfo(const RecordData &Record, @@ -2901,6 +2901,51 @@ PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { return DeclarationName(); } +NestedNameSpecifier * +PCHReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) { + unsigned N = Record[Idx++]; + NestedNameSpecifier *NNS = 0, *Prev = 0; + for (unsigned I = 0; I != N; ++I) { + NestedNameSpecifier::SpecifierKind Kind + = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; + switch (Kind) { + case NestedNameSpecifier::Identifier: { + IdentifierInfo *II = GetIdentifierInfo(Record, Idx); + NNS = NestedNameSpecifier::Create(*Context, Prev, II); + break; + } + + case NestedNameSpecifier::Namespace: { + NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++])); + NNS = NestedNameSpecifier::Create(*Context, Prev, NS); + break; + } + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + Type *T = GetType(Record[Idx++]).getTypePtr(); + bool Template = Record[Idx++]; + NNS = NestedNameSpecifier::Create(*Context, Prev, Template, T); + break; + } + + case NestedNameSpecifier::Global: { + NNS = NestedNameSpecifier::GlobalSpecifier(*Context); + // No associated value, and there can't be a prefix. + break; + } + Prev = NNS; + } + } + return NNS; +} + +SourceRange +PCHReader::ReadSourceRange(const RecordData &Record, unsigned &Idx) { + return SourceRange(SourceLocation::getFromRawEncoding(Record[Idx++]), + SourceLocation::getFromRawEncoding(Record[Idx++])); +} + /// \brief Read an integral value llvm::APInt PCHReader::ReadAPInt(const RecordData &Record, unsigned &Idx) { unsigned BitWidth = Record[Idx++]; @@ -2929,6 +2974,12 @@ std::string PCHReader::ReadString(const RecordData &Record, unsigned &Idx) { return Result; } +CXXTemporary *PCHReader::ReadCXXTemporary(const RecordData &Record, + unsigned &Idx) { + CXXDestructorDecl *Decl = cast<CXXDestructorDecl>(GetDecl(Record[Idx++])); + return CXXTemporary::Create(*Context, Decl); +} + DiagnosticBuilder PCHReader::Diag(unsigned DiagID) { return Diag(SourceLocation(), DiagID); } diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 14dd2e927c41..1ef0441ebf60 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -17,6 +17,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclGroup.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" using namespace clang; @@ -40,22 +42,49 @@ namespace { void VisitTranslationUnitDecl(TranslationUnitDecl *TU); void VisitNamedDecl(NamedDecl *ND); void VisitNamespaceDecl(NamespaceDecl *D); + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); void VisitTypeDecl(TypeDecl *TD); void VisitTypedefDecl(TypedefDecl *TD); + void VisitUnresolvedUsingTypename(UnresolvedUsingTypenameDecl *D); void VisitTagDecl(TagDecl *TD); void VisitEnumDecl(EnumDecl *ED); void VisitRecordDecl(RecordDecl *RD); + void VisitCXXRecordDecl(CXXRecordDecl *D); + void VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D); + void VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *VD); void VisitEnumConstantDecl(EnumConstantDecl *ECD); + void VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D); void VisitDeclaratorDecl(DeclaratorDecl *DD); void VisitFunctionDecl(FunctionDecl *FD); + void VisitCXXMethodDecl(CXXMethodDecl *D); + void VisitCXXConstructorDecl(CXXConstructorDecl *D); + void VisitCXXDestructorDecl(CXXDestructorDecl *D); + void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *FD); void VisitVarDecl(VarDecl *VD); void VisitImplicitParamDecl(ImplicitParamDecl *PD); void VisitParmVarDecl(ParmVarDecl *PD); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + void VisitTemplateDecl(TemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); + void visitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitUsing(UsingDecl *D); + void VisitUsingShadow(UsingShadowDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD); + void VisitFriendTemplateDecl(FriendTemplateDecl *D); + void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *BD); + std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC); + + // FIXME: Reorder according to DeclNodes.def? void VisitObjCMethodDecl(ObjCMethodDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *D); void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); @@ -90,6 +119,8 @@ void PCHDeclReader::VisitDecl(Decl *D) { void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { VisitDecl(TU); + TU->setAnonymousNamespace( + cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); } void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) { @@ -97,18 +128,6 @@ void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) { ND->setDeclName(Reader.ReadDeclarationName(Record, Idx)); } -void PCHDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { - VisitNamedDecl(D); - D->setLBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - D->setRBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - D->setNextNamespace( - cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); - D->setOriginalNamespace( - cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); - D->setAnonymousNamespace( - cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); -} - void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) { VisitNamedDecl(TD); TD->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr()); @@ -142,6 +161,8 @@ void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) { VisitTagDecl(ED); ED->setIntegerType(Reader.GetType(Record[Idx++])); ED->setPromotionType(Reader.GetType(Record[Idx++])); + ED->setNumPositiveBits(Record[Idx++]); + ED->setNumNegativeBits(Record[Idx++]); // FIXME: C++ InstantiatedFrom } @@ -191,6 +212,8 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setHasImplicitReturnZero(Record[Idx++]); FD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); // FIXME: C++ TemplateOrInstantiation + + // Read in the parameters. unsigned NumParams = Record[Idx++]; llvm::SmallVector<ParmVarDecl *, 16> Params; Params.reserve(NumParams); @@ -394,6 +417,7 @@ void PCHDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { cast_or_null<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++]))); D->setPropertyIvarDecl( cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++]))); + // FIXME. read GetterCXXConstructor and SetterCXXAssignment } void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) { @@ -411,6 +435,7 @@ void PCHDeclReader::VisitVarDecl(VarDecl *VD) { VD->setCXXDirectInitializer(Record[Idx++]); VD->setDeclaredInCondition(Record[Idx++]); VD->setExceptionVariable(Record[Idx++]); + VD->setNRVOVariable(Record[Idx++]); VD->setPreviousDeclaration( cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); if (Record[Idx++]) @@ -443,6 +468,155 @@ void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) { BD->setParams(Params.data(), NumParams); } +void PCHDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + VisitDecl(D); + D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]); + D->setHasBraces(Record[Idx++]); +} + +void PCHDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { + VisitNamedDecl(D); + D->setLBracLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setRBracLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setNextNamespace( + cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); + + // Only read one reference--the original or anonymous namespace. + bool IsOriginal = Record[Idx++]; + if (IsOriginal) + D->setAnonymousNamespace( + cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); + else + D->setOriginalNamespace( + cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + VisitNamedDecl(D); + + D->setAliasLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); + D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); + D->setTargetNameLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setAliasedNamespace(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitUsing(UsingDecl *D) { + VisitNamedDecl(D); + D->setUsingLocation(Reader.ReadSourceLocation(Record, Idx)); + D->setNestedNameRange(Reader.ReadSourceRange(Record, Idx)); + D->setTargetNestedNameDecl(Reader.ReadNestedNameSpecifier(Record, Idx)); + + // FIXME: It would probably be more efficient to read these into a vector + // and then re-cosntruct the shadow decl set over that vector since it + // would avoid existence checks. + unsigned NumShadows = Record[Idx++]; + for(unsigned I = 0; I != NumShadows; ++I) { + D->addShadowDecl(cast<UsingShadowDecl>(Reader.GetDecl(Record[Idx++]))); + } + D->setTypeName(Record[Idx++]); +} + +void PCHDeclReader::VisitUsingShadow(UsingShadowDecl *D) { + VisitNamedDecl(D); + D->setTargetDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + D->setUsingDecl(cast<UsingDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + VisitNamedDecl(D); + D->setNamespaceKeyLocation(Reader.ReadSourceLocation(Record, Idx)); + D->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); + D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); + D->setIdentLocation(Reader.ReadSourceLocation(Record, Idx)); + D->setNominatedNamespace(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + D->setCommonAncestor(cast_or_null<DeclContext>( + Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D) { + VisitValueDecl(D); + D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx)); + D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx)); +} + +void PCHDeclReader::VisitUnresolvedUsingTypename( + UnresolvedUsingTypenameDecl *D) { + VisitTypeDecl(D); + D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx)); + D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setTypenameLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx)); +} + +void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { + // assert(false && "cannot read CXXRecordDecl"); + VisitRecordDecl(D); +} + +void PCHDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { + // assert(false && "cannot read CXXMethodDecl"); + VisitFunctionDecl(D); +} + +void PCHDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + // assert(false && "cannot read CXXConstructorDecl"); + VisitCXXMethodDecl(D); +} + +void PCHDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + // assert(false && "cannot read CXXDestructorDecl"); + VisitCXXMethodDecl(D); +} + +void PCHDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { + // assert(false && "cannot read CXXConversionDecl"); + VisitCXXMethodDecl(D); +} + +void PCHDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { + assert(false && "cannot read FriendTemplateDecl"); +} + +void PCHDeclReader::VisitTemplateDecl(TemplateDecl *D) { + assert(false && "cannot read TemplateDecl"); +} + +void PCHDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { + assert(false && "cannot read ClassTemplateDecl"); +} + +void PCHDeclReader::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + assert(false && "cannot read ClassTemplateSpecializationDecl"); +} + +void PCHDeclReader::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + assert(false && "cannot read ClassTemplatePartialSpecializationDecl"); +} + +void PCHDeclReader::visitFunctionTemplateDecl(FunctionTemplateDecl *D) { + assert(false && "cannot read FunctionTemplateDecl"); +} + +void PCHDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + assert(false && "cannot read TemplateTypeParmDecl"); +} + +void PCHDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + assert(false && "cannot read NonTypeTemplateParmDecl"); +} + +void PCHDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + assert(false && "cannot read TemplateTemplateParmDecl"); +} + +void PCHDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { + assert(false && "cannot read StaticAssertDecl"); +} + std::pair<uint64_t, uint64_t> PCHDeclReader::VisitDeclContext(DeclContext *DC) { uint64_t LexicalOffset = Record[Idx++]; @@ -492,6 +666,7 @@ Attr *PCHReader::ReadAttributes() { assert(0 && "Unknown attribute!"); break; STRING_ATTR(Alias); + SIMPLE_ATTR(AlignMac68k); UNSIGNED_ATTR(Aligned); SIMPLE_ATTR(AlwaysInline); SIMPLE_ATTR(AnalyzerNoReturn); @@ -552,6 +727,13 @@ Attr *PCHReader::ReadAttributes() { New = ::new (*Context) IBOutletAttr(); break; + case Attr::IBOutletCollectionKind: { + ObjCInterfaceDecl *D = + cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++])); + New = ::new (*Context) IBOutletCollectionAttr(D); + break; + } + SIMPLE_ATTR(Malloc); SIMPLE_ATTR(NoDebug); SIMPLE_ATTR(NoInline); @@ -584,11 +766,12 @@ Attr *PCHReader::ReadAttributes() { SIMPLE_ATTR(Overloadable); SIMPLE_ATTR(Override); SIMPLE_ATTR(Packed); - UNSIGNED_ATTR(PragmaPack); + UNSIGNED_ATTR(MaxFieldAlignment); SIMPLE_ATTR(Pure); UNSIGNED_ATTR(Regparm); STRING_ATTR(Section); SIMPLE_ATTR(StdCall); + SIMPLE_ATTR(ThisCall); SIMPLE_ATTR(TransparentUnion); SIMPLE_ATTR(Unavailable); SIMPLE_ATTR(Unused); @@ -692,7 +875,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), 0); break; case pch::DECL_RECORD: - D = RecordDecl::Create(*Context, TagDecl::TK_struct, 0, SourceLocation(), + D = RecordDecl::Create(*Context, TTK_Struct, 0, SourceLocation(), 0, SourceLocation(), 0); break; case pch::DECL_ENUM_CONSTANT: @@ -703,6 +886,94 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = FunctionDecl::Create(*Context, 0, SourceLocation(), DeclarationName(), QualType(), 0); break; + case pch::DECL_LINKAGE_SPEC: + D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(), + (LinkageSpecDecl::LanguageIDs)0, + false); + break; + case pch::DECL_NAMESPACE: + D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0); + break; + case pch::DECL_NAMESPACE_ALIAS: + D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), 0, SourceRange(), 0, + SourceLocation(), 0); + break; + case pch::DECL_USING: + D = UsingDecl::Create(*Context, 0, SourceLocation(), SourceRange(), + SourceLocation(), 0, DeclarationName(), false); + break; + case pch::DECL_USING_SHADOW: + D = UsingShadowDecl::Create(*Context, 0, SourceLocation(), 0, 0); + break; + case pch::DECL_USING_DIRECTIVE: + D = UsingDirectiveDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), SourceRange(), 0, + SourceLocation(), 0, 0); + break; + case pch::DECL_UNRESOLVED_USING_VALUE: + D = UnresolvedUsingValueDecl::Create(*Context, 0, SourceLocation(), + SourceRange(), 0, SourceLocation(), + DeclarationName()); + break; + case pch::DECL_UNRESOLVED_USING_TYPENAME: + D = UnresolvedUsingTypenameDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), SourceRange(), + 0, SourceLocation(), + DeclarationName()); + break; + case pch::DECL_CXX_RECORD: + D = CXXRecordDecl::Create(*Context, TTK_Struct, 0, + SourceLocation(), 0, SourceLocation(), 0); + break; + case pch::DECL_CXX_METHOD: + D = CXXMethodDecl::Create(*Context, 0, SourceLocation(), DeclarationName(), + QualType(), 0); + break; + case pch::DECL_CXX_CONSTRUCTOR: + D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell()); + break; + case pch::DECL_CXX_DESTRUCTOR: + D = CXXDestructorDecl::Create(*Context, Decl::EmptyShell()); + break; + case pch::DECL_CXX_CONVERSION: + D = CXXConversionDecl::Create(*Context, Decl::EmptyShell()); + break; + case pch::DECL_FRIEND: + assert(false && "cannot read FriendDecl"); + break; + case pch::DECL_FRIEND_TEMPLATE: + assert(false && "cannot read FriendTemplateDecl"); + break; + case pch::DECL_TEMPLATE: + // FIXME: Should TemplateDecl be ABSTRACT_DECL??? + assert(false && "TemplateDecl should be abstract!"); + break; + case pch::DECL_CLASS_TEMPLATE: + assert(false && "cannot read ClassTemplateDecl"); + break; + case pch::DECL_CLASS_TEMPLATE_SPECIALIZATION: + assert(false && "cannot read ClasstemplateSpecializationDecl"); + break; + case pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: + assert(false && "cannot read ClassTemplatePartialSpecializationDecl"); + break; + case pch::DECL_FUNCTION_TEMPLATE: + assert(false && "cannot read FunctionTemplateDecl"); + break; + case pch::DECL_TEMPLATE_TYPE_PARM: + assert(false && "cannot read TemplateTypeParmDecl"); + break; + case pch::DECL_NON_TYPE_TEMPLATE_PARM: + assert(false && "cannot read NonTypeTemplateParmDecl"); + break; + case pch::DECL_TEMPLATE_TEMPLATE_PARM: + assert(false && "cannot read TemplateTemplateParmDecl"); + break; + case pch::DECL_STATIC_ASSERT: + assert(false && "cannot read StaticAssertDecl"); + break; + case pch::DECL_OBJC_METHOD: D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(), Selector(), QualType(), 0, 0); @@ -772,10 +1043,6 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { case pch::DECL_BLOCK: D = BlockDecl::Create(*Context, 0, SourceLocation()); break; - - case pch::DECL_NAMESPACE: - D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0); - break; } assert(D && "Unknown declaration reading PCH file"); diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index ef6b77026d7f..3931adbe8f21 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -126,6 +126,16 @@ namespace { unsigned VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); unsigned VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); unsigned VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); + unsigned VisitCXXTypeidExpr(CXXTypeidExpr *E); + unsigned VisitCXXThisExpr(CXXThisExpr *E); + unsigned VisitCXXThrowExpr(CXXThrowExpr *E); + unsigned VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); + unsigned VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); + + unsigned VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); + unsigned VisitCXXNewExpr(CXXNewExpr *E); + + unsigned VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E); }; } @@ -281,6 +291,7 @@ unsigned PCHStmtReader::VisitReturnStmt(ReturnStmt *S) { VisitStmt(S); S->setRetValue(cast_or_null<Expr>(StmtStack.back())); S->setReturnLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setNRVOCandidate(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); return 1; } @@ -529,7 +540,6 @@ unsigned PCHStmtReader::VisitCastExpr(CastExpr *E) { VisitExpr(E); E->setSubExpr(cast<Expr>(StmtStack.back())); E->setCastKind((CastExpr::CastKind)Record[Idx++]); - return 1; } @@ -947,6 +957,7 @@ unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { E->setRequiresZeroInitialization(Record[Idx++]); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I])); + E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]); return E->getNumArgs(); } @@ -992,6 +1003,99 @@ unsigned PCHStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { return 0; } +unsigned PCHStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + VisitExpr(E); + E->setSourceRange(Reader.ReadSourceRange(Record, Idx)); + if (E->isTypeOperand()) { // typeid(int) + E->setTypeOperandSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); + return 0; + } + + // typeid(42+2) + E->setExprOperand(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitCXXThisExpr(CXXThisExpr *E) { + VisitExpr(E); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setImplicit(Record[Idx++]); + return 0; +} + +unsigned PCHStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) { + VisitExpr(E); + E->setThrowLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setSubExpr(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + VisitExpr(E); + E->setUsedLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + bool HasStoredExpr = Record[Idx++]; + if (!HasStoredExpr) return 0; + E->setExpr(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + VisitExpr(E); + E->setTemporary(Reader.ReadCXXTemporary(Record, Idx)); + E->setSubExpr(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { + VisitExpr(E); + E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { + VisitExpr(E); + E->setGlobalNew(Record[Idx++]); + E->setParenTypeId(Record[Idx++]); + E->setHasInitializer(Record[Idx++]); + bool isArray = Record[Idx++]; + unsigned NumPlacementArgs = Record[Idx++]; + unsigned NumCtorArgs = Record[Idx++]; + E->setOperatorNew(cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); + E->setOperatorDelete( + cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); + E->setConstructor( + cast_or_null<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++]))); + E->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + + E->AllocateArgsArray(*Reader.getContext(), isArray, NumPlacementArgs, + NumCtorArgs); + + // Install all the subexpressions. + unsigned TotalSubExprs = E->raw_arg_end()-E->raw_arg_begin(); + unsigned SSIdx = StmtStack.size()-TotalSubExprs; + for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(),e = E->raw_arg_end(); + I != e; ++I) + *I = StmtStack[SSIdx++]; + + return TotalSubExprs; +} + + +unsigned PCHStmtReader::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { + VisitExpr(E); + unsigned NumTemps = Record[Idx++]; + if (NumTemps) { + E->setNumTemporaries(*Reader.getContext(), NumTemps); + for (unsigned i = 0; i != NumTemps; ++i) + E->setTemporary(i, Reader.ReadCXXTemporary(Record, Idx)); + } + E->setSubExpr(cast<Expr>(StmtStack.back())); + return 1; +} + + // Within the bitstream, expressions are stored in Reverse Polish // Notation, with each of the subexpressions preceding the // expression they are stored in. To evaluate expressions, we @@ -1304,6 +1408,10 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { case pch::EXPR_CXX_OPERATOR_CALL: S = new (Context) CXXOperatorCallExpr(*Context, Empty); break; + + case pch::EXPR_CXX_MEMBER_CALL: + S = new (Context) CXXMemberCallExpr(*Context, Empty); + break; case pch::EXPR_CXX_CONSTRUCT: S = new (Context) CXXConstructExpr(Empty, *Context, @@ -1337,6 +1445,36 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { case pch::EXPR_CXX_NULL_PTR_LITERAL: S = new (Context) CXXNullPtrLiteralExpr(Empty); break; + case pch::EXPR_CXX_TYPEID_EXPR: + S = new (Context) CXXTypeidExpr(Empty, true); + break; + case pch::EXPR_CXX_TYPEID_TYPE: + S = new (Context) CXXTypeidExpr(Empty, false); + break; + case pch::EXPR_CXX_THIS: + S = new (Context) CXXThisExpr(Empty); + break; + case pch::EXPR_CXX_THROW: + S = new (Context) CXXThrowExpr(Empty); + break; + case pch::EXPR_CXX_DEFAULT_ARG: + S = new (Context) CXXDefaultArgExpr(Empty); + break; + case pch::EXPR_CXX_BIND_TEMPORARY: + S = new (Context) CXXBindTemporaryExpr(Empty); + break; + + case pch::EXPR_CXX_ZERO_INIT_VALUE: + S = new (Context) CXXZeroInitValueExpr(Empty); + break; + case pch::EXPR_CXX_NEW: + S = new (Context) CXXNewExpr(Empty); + break; + + + case pch::EXPR_CXX_EXPR_WITH_TEMPORARIES: + S = new (Context) CXXExprWithTemporaries(Empty); + break; } // We hit a STMT_STOP, so we're done with this expression. diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index e56dd3132224..3d5b7d8156a8 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -213,12 +213,6 @@ void PCHTypeWriter::VisitEnumType(const EnumType *T) { Code = pch::TYPE_ENUM; } -void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) { - Writer.AddTypeRef(T->getUnderlyingType(), Record); - Record.push_back(T->getTagKind()); - Code = pch::TYPE_ELABORATED; -} - void PCHTypeWriter::VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *T) { @@ -234,9 +228,12 @@ PCHTypeWriter::VisitTemplateSpecializationType( assert(false && "Cannot serialize template specialization types"); } -void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) { - // FIXME: Serialize this type (C++ only) - assert(false && "Cannot serialize qualified name types"); +void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) { + Writer.AddTypeRef(T->getNamedType(), Record); + Record.push_back(T->getKeyword()); + // FIXME: Serialize the qualifier (C++ only) + assert(T->getQualifier() == 0 && "Cannot serialize qualified name types"); + Code = pch::TYPE_ELABORATED; } void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { @@ -247,20 +244,21 @@ void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_OBJC_INTERFACE; +} + +void PCHTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { + Writer.AddTypeRef(T->getBaseType(), Record); Record.push_back(T->getNumProtocols()); - for (ObjCInterfaceType::qual_iterator I = T->qual_begin(), + for (ObjCObjectType::qual_iterator I = T->qual_begin(), E = T->qual_end(); I != E; ++I) Writer.AddDeclRef(*I, Record); - Code = pch::TYPE_OBJC_INTERFACE; + Code = pch::TYPE_OBJC_OBJECT; } void PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { Writer.AddTypeRef(T->getPointeeType(), Record); - Record.push_back(T->getNumProtocols()); - for (ObjCInterfaceType::qual_iterator I = T->qual_begin(), - E = T->qual_end(); I != E; ++I) - Writer.AddDeclRef(*I, Record); Code = pch::TYPE_OBJC_OBJECT_POINTER; } @@ -383,9 +381,6 @@ void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } -void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } @@ -401,17 +396,23 @@ void TypeLocWriter::VisitTemplateSpecializationTypeLoc( for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) Writer.AddTemplateArgumentLoc(TL.getArgLoc(i), Record); } -void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); +void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + Writer.AddSourceLocation(TL.getKeywordLoc(), Record); + Writer.AddSourceRange(TL.getQualifierRange(), Record); } void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + Writer.AddSourceLocation(TL.getKeywordLoc(), Record); + Writer.AddSourceRange(TL.getQualifierRange(), Record); Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + Record.push_back(TL.hasBaseTypeAsWritten()); Writer.AddSourceLocation(TL.getLAngleLoc(), Record); Writer.AddSourceLocation(TL.getRAngleLoc(), Record); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) @@ -419,13 +420,6 @@ void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { Writer.AddSourceLocation(TL.getStarLoc(), Record); - Writer.AddSourceLocation(TL.getLAngleLoc(), Record); - Writer.AddSourceLocation(TL.getRAngleLoc(), Record); - Record.push_back(TL.hasBaseTypeAsWritten()); - Record.push_back(TL.hasProtocolsAsWritten()); - if (TL.hasProtocolsAsWritten()) - for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) - Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); } //===----------------------------------------------------------------------===// @@ -609,6 +603,7 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(TYPE_RECORD); RECORD(TYPE_ENUM); RECORD(TYPE_OBJC_INTERFACE); + RECORD(TYPE_OBJC_OBJECT); RECORD(TYPE_OBJC_OBJECT_POINTER); RECORD(DECL_ATTR); RECORD(DECL_TRANSLATION_UNIT); @@ -1841,6 +1836,9 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { AddString(cast<AliasAttr>(Attr)->getAliasee(), Record); break; + case Attr::AlignMac68k: + break; + case Attr::Aligned: Record.push_back(cast<AlignedAttr>(Attr)->getAlignment()); break; @@ -1925,6 +1923,12 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { case Attr::NoThrow: break; + case Attr::IBOutletCollectionKind: { + const IBOutletCollectionAttr *ICA = cast<IBOutletCollectionAttr>(Attr); + AddDeclRef(ICA->getClass(), Record); + break; + } + case Attr::NonNull: { const NonNullAttr *NonNull = cast<NonNullAttr>(Attr); Record.push_back(NonNull->size()); @@ -1942,8 +1946,8 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { case Attr::Override: break; - case Attr::PragmaPack: - Record.push_back(cast<PragmaPackAttr>(Attr)->getAlignment()); + case Attr::MaxFieldAlignment: + Record.push_back(cast<MaxFieldAlignmentAttr>(Attr)->getAlignment()); break; case Attr::Packed: @@ -2181,6 +2185,11 @@ void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) { Record.push_back(Loc.getRawEncoding()); } +void PCHWriter::AddSourceRange(SourceRange Range, RecordData &Record) { + AddSourceLocation(Range.getBegin(), Record); + AddSourceLocation(Range.getEnd(), Record); +} + void PCHWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) { Record.push_back(Value.getBitWidth()); unsigned N = Value.getNumWords(); @@ -2236,6 +2245,10 @@ void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) { Record.push_back(SID); } +void PCHWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordData &Record) { + AddDeclRef(Temp->getDestructor(), Record); +} + void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, RecordData &Record) { switch (Arg.getArgument().getKind()) { @@ -2407,3 +2420,42 @@ void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) { break; } } + +void PCHWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS, + RecordData &Record) { + // Nested name specifiers usually aren't too long. I think that 8 would + // typically accomodate the vast majority. + llvm::SmallVector<NestedNameSpecifier *, 8> NestedNames; + + // Push each of the NNS's onto a stack for serialization in reverse order. + while (NNS) { + NestedNames.push_back(NNS); + NNS = NNS->getPrefix(); + } + + Record.push_back(NestedNames.size()); + while(!NestedNames.empty()) { + NNS = NestedNames.pop_back_val(); + NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); + Record.push_back(Kind); + switch (Kind) { + case NestedNameSpecifier::Identifier: + AddIdentifierRef(NNS->getAsIdentifier(), Record); + break; + + case NestedNameSpecifier::Namespace: + AddDeclRef(NNS->getAsNamespace(), Record); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + AddTypeRef(QualType(NNS->getAsType(), 0), Record); + Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate); + break; + + case NestedNameSpecifier::Global: + // Don't need to write an associated value. + break; + } + } +} diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 7b7806239604..cc58e8ee4654 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -13,6 +13,8 @@ #include "clang/Frontend/PCHWriter.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamWriter.h" @@ -43,23 +45,51 @@ namespace { void VisitTranslationUnitDecl(TranslationUnitDecl *D); void VisitNamedDecl(NamedDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); void VisitTypeDecl(TypeDecl *D); void VisitTypedefDecl(TypedefDecl *D); + void VisitUnresolvedUsingTypename(UnresolvedUsingTypenameDecl *D); void VisitTagDecl(TagDecl *D); void VisitEnumDecl(EnumDecl *D); void VisitRecordDecl(RecordDecl *D); + void VisitCXXRecordDecl(CXXRecordDecl *D); + void VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D); + void VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *D); void VisitEnumConstantDecl(EnumConstantDecl *D); + void VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D); void VisitDeclaratorDecl(DeclaratorDecl *D); void VisitFunctionDecl(FunctionDecl *D); + void VisitCXXMethodDecl(CXXMethodDecl *D); + void VisitCXXConstructorDecl(CXXConstructorDecl *D); + void VisitCXXDestructorDecl(CXXDestructorDecl *D); + void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); void VisitParmVarDecl(ParmVarDecl *D); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + void VisitTemplateDecl(TemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); + void visitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitUsing(UsingDecl *D); + void VisitUsingShadow(UsingShadowDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitFriendTemplateDecl(FriendTemplateDecl *D); + void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *D); + void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, uint64_t VisibleOffset); + + + // FIXME: Put in the same order is DeclNodes.def? void VisitObjCMethodDecl(ObjCMethodDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *D); void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); @@ -92,6 +122,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) { void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { VisitDecl(D); + Writer.AddDeclRef(D->getAnonymousNamespace(), Record); Code = pch::DECL_TRANSLATION_UNIT; } @@ -100,16 +131,6 @@ void PCHDeclWriter::VisitNamedDecl(NamedDecl *D) { Writer.AddDeclarationName(D->getDeclName(), Record); } -void PCHDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { - VisitNamedDecl(D); - Writer.AddSourceLocation(D->getLBracLoc(), Record); - Writer.AddSourceLocation(D->getRBracLoc(), Record); - Writer.AddDeclRef(D->getNextNamespace(), Record); - Writer.AddDeclRef(D->getOriginalNamespace(), Record); - Writer.AddDeclRef(D->getAnonymousNamespace(), Record); - Code = pch::DECL_NAMESPACE; -} - void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { VisitNamedDecl(D); Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); @@ -137,6 +158,8 @@ void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) { VisitTagDecl(D); Writer.AddTypeRef(D->getIntegerType(), Record); Writer.AddTypeRef(D->getPromotionType(), Record); + Record.push_back(D->getNumPositiveBits()); + Record.push_back(D->getNumNegativeBits()); // FIXME: C++ InstantiatedFrom Code = pch::DECL_ENUM; } @@ -171,9 +194,11 @@ void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { VisitDeclaratorDecl(D); + Record.push_back(D->isThisDeclarationADefinition()); if (D->isThisDeclarationADefinition()) Writer.AddStmt(D->getBody()); + Writer.AddDeclRef(D->getPreviousDeclaration(), Record); Record.push_back(D->getStorageClass()); // FIXME: stable encoding Record.push_back(D->getStorageClassAsWritten()); @@ -186,8 +211,9 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->isTrivial()); Record.push_back(D->isCopyAssignment()); Record.push_back(D->hasImplicitReturnZero()); + // FIXME: C++ TemplateOrInstantiation??? Writer.AddSourceLocation(D->getLocEnd(), Record); - // FIXME: C++ TemplateOrInstantiation + Record.push_back(D->param_size()); for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) @@ -225,9 +251,7 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { VisitNamedDecl(D); - SourceRange R = D->getAtEndRange(); - Writer.AddSourceLocation(R.getBegin(), Record); - Writer.AddSourceLocation(R.getEnd(), Record); + Writer.AddSourceRange(D->getAtEndRange(), Record); // Abstract class (no need to define a stable pch::DECL code). } @@ -370,6 +394,7 @@ void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { Writer.AddSourceLocation(D->getLocStart(), Record); Writer.AddDeclRef(D->getPropertyDecl(), Record); Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); + // FIXME. write GetterCXXConstructor and SetterCXXAssignment. Code = pch::DECL_OBJC_PROPERTY_IMPL; } @@ -390,8 +415,9 @@ void PCHDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(D->hasCXXDirectInitializer()); Record.push_back(D->isDeclaredInCondition()); Record.push_back(D->isExceptionVariable()); + Record.push_back(D->isNRVOVariable()); Writer.AddDeclRef(D->getPreviousDeclaration(), Record); - Record.push_back(D->getInit()? 1 : 0); + Record.push_back(D->getInit() ? 1 : 0); if (D->getInit()) Writer.AddStmt(D->getInit()); Code = pch::DECL_VAR; @@ -408,7 +434,6 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { Record.push_back(D->hasInheritedDefaultArg()); Code = pch::DECL_PARM_VAR; - // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here // we dynamically check for the properties that we optimize for, but don't // know are true of all PARM_VAR_DECLs. @@ -421,7 +446,8 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { D->getStorageClass() == 0 && !D->hasCXXDirectInitializer() && // Can params have this ever? D->getObjCDeclQualifier() == 0 && - !D->hasInheritedDefaultArg()) + !D->hasInheritedDefaultArg() && + D->getInit() == 0) // No default expr. AbbrevToUse = Writer.getParmVarDeclAbbrev(); // Check things we know are true of *every* PARM_VAR_DECL, which is more than @@ -432,7 +458,6 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { assert(!D->isDeclaredInCondition() && "PARM_VAR_DECL can't be in condition"); assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var"); assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl"); - assert(D->getInit() == 0 && "PARM_VAR_DECL never has init"); } void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { @@ -451,6 +476,161 @@ void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) { Code = pch::DECL_BLOCK; } +void PCHDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + VisitDecl(D); + // FIXME: It might be nice to serialize the brace locations for this + // declaration, which don't seem to be readily available in the AST. + Record.push_back(D->getLanguage()); + Record.push_back(D->hasBraces()); + Code = pch::DECL_LINKAGE_SPEC; +} + +void PCHDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceLocation(D->getLBracLoc(), Record); + Writer.AddSourceLocation(D->getRBracLoc(), Record); + Writer.AddDeclRef(D->getNextNamespace(), Record); + + // Only write one reference--original or anonymous + Record.push_back(D->isOriginalNamespace()); + if (D->isOriginalNamespace()) + Writer.AddDeclRef(D->getAnonymousNamespace(), Record); + else + Writer.AddDeclRef(D->getOriginalNamespace(), Record); + Code = pch::DECL_NAMESPACE; +} + +void PCHDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceLocation(D->getAliasLoc(), Record); + Writer.AddSourceRange(D->getQualifierRange(), Record); + Writer.AddNestedNameSpecifier(D->getQualifier(), Record); + Writer.AddSourceLocation(D->getTargetNameLoc(), Record); + Writer.AddDeclRef(D->getNamespace(), Record); + Code = pch::DECL_NAMESPACE_ALIAS; +} + +void PCHDeclWriter::VisitUsing(UsingDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceRange(D->getNestedNameRange(), Record); + Writer.AddSourceLocation(D->getUsingLocation(), Record); + Writer.AddNestedNameSpecifier(D->getTargetNestedNameDecl(), Record); + Record.push_back(D->getNumShadowDecls()); + for (UsingDecl::shadow_iterator P = D->shadow_begin(), + PEnd = D->shadow_end(); P != PEnd; ++P) + Writer.AddDeclRef(*P, Record); + Record.push_back(D->isTypeName()); + Code = pch::DECL_USING; +} + +void PCHDeclWriter::VisitUsingShadow(UsingShadowDecl *D) { + VisitNamedDecl(D); + Writer.AddDeclRef(D->getTargetDecl(), Record); + Writer.AddDeclRef(D->getUsingDecl(), Record); + Code = pch::DECL_USING_SHADOW; +} + +void PCHDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record); + Writer.AddSourceRange(D->getQualifierRange(), Record); + Writer.AddNestedNameSpecifier(D->getQualifier(), Record); + Writer.AddSourceLocation(D->getIdentLocation(), Record); + Writer.AddDeclRef(D->getNominatedNamespace(), Record); + Writer.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor()), Record); + Code = pch::DECL_USING_DIRECTIVE; +} + +void PCHDeclWriter::VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D) { + VisitValueDecl(D); + Writer.AddSourceRange(D->getTargetNestedNameRange(), Record); + Writer.AddSourceLocation(D->getUsingLoc(), Record); + Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record); + Code = pch::DECL_UNRESOLVED_USING_VALUE; +} + +void PCHDeclWriter::VisitUnresolvedUsingTypename( + UnresolvedUsingTypenameDecl *D) { + VisitTypeDecl(D); + Writer.AddSourceRange(D->getTargetNestedNameRange(), Record); + Writer.AddSourceLocation(D->getUsingLoc(), Record); + Writer.AddSourceLocation(D->getTypenameLoc(), Record); + Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record); + Code = pch::DECL_UNRESOLVED_USING_TYPENAME; +} + +void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { + // assert(false && "cannot write CXXRecordDecl"); + VisitRecordDecl(D); + Code = pch::DECL_CXX_RECORD; +} + +void PCHDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) { + // assert(false && "cannot write CXXMethodDecl"); + VisitFunctionDecl(D); + Code = pch::DECL_CXX_METHOD; +} + +void PCHDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + // assert(false && "cannot write CXXConstructorDecl"); + VisitCXXMethodDecl(D); + Code = pch::DECL_CXX_CONSTRUCTOR; +} + +void PCHDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + // assert(false && "cannot write CXXDestructorDecl"); + VisitCXXMethodDecl(D); + Code = pch::DECL_CXX_DESTRUCTOR; +} + +void PCHDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { + // assert(false && "cannot write CXXConversionDecl"); + VisitCXXMethodDecl(D); + Code = pch::DECL_CXX_CONVERSION; +} + +void PCHDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) { + assert(false && "cannot write FriendTemplateDecl"); +} + +void PCHDeclWriter::VisitTemplateDecl(TemplateDecl *D) { + assert(false && "cannot write TemplateDecl"); +} + +void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { + assert(false && "cannot write ClassTemplateDecl"); +} + +void PCHDeclWriter::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + assert(false && "cannot write ClassTemplateSpecializationDecl"); +} + +void PCHDeclWriter::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + assert(false && "cannot write ClassTemplatePartialSpecializationDecl"); +} + +void PCHDeclWriter::visitFunctionTemplateDecl(FunctionTemplateDecl *D) { + assert(false && "cannot write FunctionTemplateDecl"); +} + +void PCHDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + assert(false && "cannot write TemplateTypeParmDecl"); +} + +void PCHDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + assert(false && "cannot write NonTypeTemplateParmDecl"); +} + +void PCHDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + assert(false && "cannot write TemplateTemplateParmDecl"); +} + +void PCHDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) { + assert(false && "cannot write StaticAssertDecl"); +} + /// \brief Emit the DeclContext part of a declaration context decl. /// /// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL @@ -504,6 +684,7 @@ void PCHWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable + Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl Abv->Add(BitCodeAbbrevOp(0)); // HasInit // ParmVarDecl diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index a1993d37f2dc..a9ee43527cec 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -112,6 +112,7 @@ namespace { // C++ Statements void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); + void VisitCXXMemberCallExpr(CXXMemberCallExpr *E); void VisitCXXConstructExpr(CXXConstructExpr *E); void VisitCXXNamedCastExpr(CXXNamedCastExpr *E); void VisitCXXStaticCastExpr(CXXStaticCastExpr *E); @@ -121,6 +122,16 @@ namespace { void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); + void VisitCXXTypeidExpr(CXXTypeidExpr *E); + void VisitCXXThisExpr(CXXThisExpr *E); + void VisitCXXThrowExpr(CXXThrowExpr *E); + void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); + void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); + + void VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); + void VisitCXXNewExpr(CXXNewExpr *E); + + void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E); }; } @@ -264,6 +275,7 @@ void PCHStmtWriter::VisitReturnStmt(ReturnStmt *S) { VisitStmt(S); Writer.WriteSubStmt(S->getRetValue()); Writer.AddSourceLocation(S->getReturnLoc(), Record); + Writer.AddDeclRef(S->getNRVOCandidate(), Record); Code = pch::STMT_RETURN; } @@ -848,6 +860,11 @@ void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { Code = pch::EXPR_CXX_OPERATOR_CALL; } +void PCHStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { + VisitCallExpr(E); + Code = pch::EXPR_CXX_MEMBER_CALL; +} + void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { VisitExpr(E); Writer.AddDeclRef(E->getConstructor(), Record); @@ -857,6 +874,7 @@ void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { Record.push_back(E->getNumArgs()); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) Writer.WriteSubStmt(E->getArg(I)); + Record.push_back(E->getConstructionKind()); // FIXME: stable encoding Code = pch::EXPR_CXX_CONSTRUCT; } @@ -905,6 +923,91 @@ void PCHStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { Code = pch::EXPR_CXX_NULL_PTR_LITERAL; } +void PCHStmtWriter::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + VisitExpr(E); + Writer.AddSourceRange(E->getSourceRange(), Record); + if (E->isTypeOperand()) { + Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record); + Code = pch::EXPR_CXX_TYPEID_TYPE; + } else { + Writer.WriteSubStmt(E->getExprOperand()); + Code = pch::EXPR_CXX_TYPEID_EXPR; + } +} + +void PCHStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getLocation(), Record); + Record.push_back(E->isImplicit()); + Code = pch::EXPR_CXX_THIS; +} + +void PCHStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getThrowLoc(), Record); + Writer.WriteSubStmt(E->getSubExpr()); + Code = pch::EXPR_CXX_THROW; +} + +void PCHStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getUsedLocation(), Record); + if (E->isExprStored()) { + Record.push_back(1); + Writer.WriteSubStmt(E->getExpr()); + } else { + Record.push_back(0); + } + + Code = pch::EXPR_CXX_DEFAULT_ARG; +} + +void PCHStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + VisitExpr(E); + Writer.AddCXXTemporary(E->getTemporary(), Record); + Writer.WriteSubStmt(E->getSubExpr()); + Code = pch::EXPR_CXX_BIND_TEMPORARY; +} + +void PCHStmtWriter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getTypeBeginLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_CXX_ZERO_INIT_VALUE; +} + +void PCHStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) { + VisitExpr(E); + Record.push_back(E->isGlobalNew()); + Record.push_back(E->isParenTypeId()); + Record.push_back(E->hasInitializer()); + Record.push_back(E->isArray()); + Record.push_back(E->getNumPlacementArgs()); + Record.push_back(E->getNumConstructorArgs()); + Writer.AddDeclRef(E->getOperatorNew(), Record); + Writer.AddDeclRef(E->getOperatorDelete(), Record); + Writer.AddDeclRef(E->getConstructor(), Record); + Writer.AddSourceLocation(E->getStartLoc(), Record); + Writer.AddSourceLocation(E->getEndLoc(), Record); + for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end(); + I != e; ++I) + Writer.WriteSubStmt(*I); + + Code = pch::EXPR_CXX_NEW; +} + + +void PCHStmtWriter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { + VisitExpr(E); + Record.push_back(E->getNumTemporaries()); + for (unsigned i = 0, e = E->getNumTemporaries(); i != e; ++i) + Writer.AddCXXTemporary(E->getTemporary(i), Record); + + Writer.WriteSubStmt(E->getSubExpr()); + Code = pch::EXPR_CXX_EXPR_WITH_TEMPORARIES; +} + + //===----------------------------------------------------------------------===// // PCHWriter Implementation //===----------------------------------------------------------------------===// @@ -949,8 +1052,13 @@ void PCHWriter::WriteSubStmt(Stmt *S) { Writer.Code = pch::STMT_NULL_PTR; Writer.Visit(S); - assert(Writer.Code != pch::STMT_NULL_PTR && - "Unhandled expression writing PCH file"); + +#ifndef NDEBUG + if (Writer.Code == pch::STMT_NULL_PTR) { + S->dump(); + assert(0 && "Unhandled sub statement writing PCH file"); + } +#endif Stream.EmitRecord(Writer.Code, Record); } @@ -971,8 +1079,12 @@ void PCHWriter::FlushStmts() { Writer.Code = pch::STMT_NULL_PTR; Writer.Visit(S); - assert(Writer.Code != pch::STMT_NULL_PTR && - "Unhandled expression writing PCH file"); +#ifndef NDEBUG + if (Writer.Code == pch::STMT_NULL_PTR) { + S->dump(); + assert(0 && "Unhandled expression writing PCH file"); + } +#endif Stream.EmitRecord(Writer.Code, Record); assert(N == StmtsToEmit.size() && diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index 4df5c5263c7e..b032233b3d3b 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -161,7 +161,8 @@ namespace { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS) { Out << __FUNCTION__ << "\n"; return DeclPtrTy(); } @@ -315,7 +316,8 @@ namespace { return StmtEmpty(); } - virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + ExprArg Cond, DeclPtrTy CondVar) { Out << __FUNCTION__ << "\n"; return StmtEmpty(); diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 11698325e9b1..5dd7bdfcbfa1 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -276,6 +276,7 @@ namespace { bool isSuperReceiver(Expr *recExpr); QualType getSuperStructType(); QualType getConstantStringStructType(); + QualType convertFunctionTypeOfBlocks(const FunctionType *FT); bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); // Expression Rewriting. @@ -403,6 +404,18 @@ namespace { return isa<BlockPointerType>(T); } + /// convertBlockPointerToFunctionPointer - Converts a block-pointer type + /// to a function pointer type and upon success, returns true; false + /// otherwise. + bool convertBlockPointerToFunctionPointer(QualType &T) { + if (isTopLevelBlockPointerType(T)) { + const BlockPointerType *BPT = T->getAs<BlockPointerType>(); + T = Context->getPointerType(BPT->getPointeeType()); + return true; + } + return false; + } + // FIXME: This predicate seems like it would be useful to add to ASTContext. bool isObjCType(QualType T) { if (!LangOpts.ObjC1 && !LangOpts.ObjC2) @@ -971,7 +984,8 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { RewriteMethodDeclaration(*I); // Lastly, comment out the @end. - ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// "); + ReplaceText(CatDecl->getAtEndRange().getBegin(), + strlen("@end"), "/* @end */"); } void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { @@ -991,7 +1005,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { // Lastly, comment out the @end. SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); - ReplaceText(LocEnd, 0, "// "); + ReplaceText(LocEnd, strlen("@end"), "/* @end */"); // Must comment out @optional/@required const char *startBuf = SM->getCharacterData(LocStart); @@ -1109,12 +1123,11 @@ void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD, ResultStr += PDecl->getNameAsString(); } else { std::string Name = PDecl->getNameAsString(); - if (isTopLevelBlockPointerType(PDecl->getType())) { - // Make sure we convert "t (^)(...)" to "t (*)(...)". - const BlockPointerType *BPT = PDecl->getType()->getAs<BlockPointerType>(); - Context->getPointerType(BPT->getPointeeType()).getAsStringInternal(Name, - Context->PrintingPolicy); - } else + QualType QT = PDecl->getType(); + // Make sure we convert "t (^)(...)" to "t (*)(...)". + if (convertBlockPointerToFunctionPointer(QT)) + QT.getAsStringInternal(Name, Context->PrintingPolicy); + else PDecl->getType().getAsStringInternal(Name, Context->PrintingPolicy); ResultStr += Name; } @@ -1220,7 +1233,8 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { RewriteMethodDeclaration(*I); // Lastly, comment out the @end. - ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// "); + ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"), + "/* @end */"); } Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, @@ -1349,7 +1363,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, std::string RecName = clsDeclared->getIdentifier()->getName(); RecName += "_IMPL"; IdentifierInfo *II = &Context->Idents.get(RecName); - RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); @@ -1394,7 +1408,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, std::string RecName = clsDeclared->getIdentifier()->getName(); RecName += "_IMPL"; IdentifierInfo *II = &Context->Idents.get(RecName); - RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); @@ -1911,13 +1925,13 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { buf += "1) { "; ReplaceText(startLoc, lParenLoc-startBuf+1, buf); sawIdTypedCatch = true; - } else if (t->isObjCObjectPointerType()) { - QualType InterfaceTy = t->getPointeeType(); - const ObjCInterfaceType *cls = // Should be a pointer to a class. - InterfaceTy->getAs<ObjCInterfaceType>(); - if (cls) { + } else if (const ObjCObjectPointerType *Ptr = + t->getAs<ObjCObjectPointerType>()) { + // Should be a pointer to a class. + ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface(); + if (IDecl) { buf += "objc_exception_match((struct objc_class *)objc_getClass(\""; - buf += cls->getDecl()->getNameAsString(); + buf += IDecl->getNameAsString(); buf += "\"), (struct objc_object *)_caught)) { "; ReplaceText(startLoc, lParenLoc-startBuf+1, buf); } @@ -2426,7 +2440,7 @@ void RewriteObjC::SynthMsgSendFunctionDecl() { void RewriteObjC::SynthMsgSendSuperFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); llvm::SmallVector<QualType, 16> ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), &Context->Idents.get("objc_super")); QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); @@ -2475,7 +2489,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper_stret"); llvm::SmallVector<QualType, 16> ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), &Context->Idents.get("objc_super")); QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); @@ -2625,7 +2639,7 @@ bool RewriteObjC::isSuperReceiver(Expr *recExpr) { // struct objc_super { struct objc_object *receiver; struct objc_class *super; }; QualType RewriteObjC::getSuperStructType() { if (!SuperStructDecl) { - SuperStructDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, + SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), &Context->Idents.get("objc_super")); QualType FieldTypes[2]; @@ -2651,7 +2665,7 @@ QualType RewriteObjC::getSuperStructType() { QualType RewriteObjC::getConstantStringStructType() { if (!ConstantStringDecl) { - ConstantStringDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, + ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), &Context->Idents.get("__NSConstantStringImpl")); QualType FieldTypes[4]; @@ -2811,7 +2825,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ObjCInterfaceDecl *Class - = Exp->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); IdentifierInfo *clsName = Class->getIdentifier(); ClsExprs.push_back(StringLiteral::Create(*Context, clsName->getNameStart(), @@ -2943,6 +2957,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, QualType type = ICE->getType()->isObjCQualifiedIdType() ? Context->getObjCIdType() : ICE->getType(); + // Make sure we convert "type (^)(...)" to "type (*)(...)". + (void)convertBlockPointerToFunctionPointer(type); userExpr = NoTypeInfoCStyleCastExpr(Context, type, CastExpr::CK_Unknown, userExpr); } @@ -2980,18 +2996,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ? Context->getObjCIdType() : (*PI)->getType(); // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (isTopLevelBlockPointerType(t)) { - const BlockPointerType *BPT = t->getAs<BlockPointerType>(); - t = Context->getPointerType(BPT->getPointeeType()); - } + (void)convertBlockPointerToFunctionPointer(t); ArgTypes.push_back(t); } returnType = OMD->getResultType()->isObjCQualifiedIdType() ? Context->getObjCIdType() : OMD->getResultType(); - if (isTopLevelBlockPointerType(returnType)) { - const BlockPointerType *BPT = returnType->getAs<BlockPointerType>(); - returnType = Context->getPointerType(BPT->getPointeeType()); - } + (void)convertBlockPointerToFunctionPointer(returnType); } else { returnType = Context->getObjCIdType(); } @@ -4111,7 +4121,11 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, E = BD->param_end(); AI != E; ++AI) { if (AI != BD->param_begin()) S += ", "; ParamStr = (*AI)->getNameAsString(); - (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy); + QualType QT = (*AI)->getType(); + if (convertBlockPointerToFunctionPointer(QT)) + QT.getAsStringInternal(ParamStr, Context->PrintingPolicy); + else + QT.getAsStringInternal(ParamStr, Context->PrintingPolicy); S += ParamStr; } if (FT->isVariadic()) { @@ -4532,6 +4546,39 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, return; } +/// convertFunctionTypeOfBlocks - This routine converts a function type +/// whose result type may be a block pointer or whose argument type(s) +/// might be block pointers to an equivalent funtion type replacing +/// all block pointers to function pointers. +QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { + const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); + // FTP will be null for closures that don't take arguments. + // Generate a funky cast. + llvm::SmallVector<QualType, 8> ArgTypes; + QualType Res = FT->getResultType(); + bool HasBlockType = convertBlockPointerToFunctionPointer(Res); + + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I && (I != E); ++I) { + QualType t = *I; + // Make sure we convert "t (^)(...)" to "t (*)(...)". + if (convertBlockPointerToFunctionPointer(t)) + HasBlockType = true; + ArgTypes.push_back(t); + } + } + QualType FuncType; + // FIXME. Does this work if block takes no argument but has a return type + // which is of block type? + if (HasBlockType) + FuncType = Context->getFunctionType(Res, + &ArgTypes[0], ArgTypes.size(), false/*no variadic*/, 0, + false, false, 0, 0, FunctionType::ExtInfo()); + else FuncType = QualType(FT, 0); + return FuncType; +} + Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { // Navigate to relevant type information. const BlockPointerType *CPT = 0; @@ -4573,7 +4620,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); // FTP will be null for closures that don't take arguments. - RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), &Context->Idents.get("__block_impl")); QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); @@ -4588,10 +4635,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { E = FTP->arg_type_end(); I && (I != E); ++I) { QualType t = *I; // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (isTopLevelBlockPointerType(t)) { - const BlockPointerType *BPT = t->getAs<BlockPointerType>(); - t = Context->getPointerType(BPT->getPointeeType()); - } + (void)convertBlockPointerToFunctionPointer(t); ArgTypes.push_back(t); } } @@ -5174,7 +5218,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; // Get a pointer to the function type so we can cast appropriately. - QualType FType = Context->getPointerType(QualType(Exp->getFunctionType(),0)); + QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType()); + QualType FType = Context->getPointerType(BFT); FunctionDecl *FD; Expr *NewRep; @@ -5218,6 +5263,12 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, // FIXME: Conform to ABI ([[obj retain] autorelease]). 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()); + } } else if (isTopLevelBlockPointerType((*I)->getType())) { FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); @@ -5245,7 +5296,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, RewriteByRefString(RecName, Name, ND); IdentifierInfo *II = &Context->Idents.get(RecName.c_str() + sizeof("struct")); - RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), II); assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 66ed956a22a7..6ccf4f1ad0a6 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -18,6 +18,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include <algorithm> using namespace clang; @@ -819,21 +820,52 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, llvm::SmallString<100> OutStr; Info.FormatDiagnostic(OutStr); + std::string OptionName; if (DiagOpts->ShowOptionNames) { if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) { - OutStr += " [-W"; - OutStr += Opt; - OutStr += ']'; + OptionName = "-W"; + OptionName += Opt; + } else if (Info.getID() == diag::fatal_too_many_errors) { + OptionName = "-ferror-limit="; } else { // If the diagnostic is an extension diagnostic and not enabled by default // then it must have been turned on with -pedantic. bool EnabledByDefault; if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) && !EnabledByDefault) - OutStr += " [-pedantic]"; + OptionName = "-pedantic"; } } + + // If the user wants to see category information, include it too. + unsigned DiagCategory = 0; + if (DiagOpts->ShowCategories) + DiagCategory = Diagnostic::getCategoryNumberForDiag(Info.getID()); + + // If there is any categorization information, include it. + if (!OptionName.empty() || DiagCategory != 0) { + bool NeedsComma = false; + OutStr += " ["; + + if (!OptionName.empty()) { + OutStr += OptionName; + NeedsComma = true; + } + + if (DiagCategory) { + if (NeedsComma) OutStr += ','; + if (DiagOpts->ShowCategories == 1) + OutStr += llvm::utostr(DiagCategory); + else { + assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value"); + OutStr += Diagnostic::getCategoryNameFromID(DiagCategory); + } + } + + OutStr += "]"; + } + if (DiagOpts->ShowColors) { // Print warnings, errors and fatal errors in bold, no color switch (Level) { diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h index 6b9dd2aba588..8afbe76fbeb5 100644 --- a/lib/Headers/emmintrin.h +++ b/lib/Headers/emmintrin.h @@ -1310,8 +1310,9 @@ _mm_movemask_pd(__m128d a) return __builtin_ia32_movmskpd(a); } -#define _mm_shuffle_pd(a, b, i) (__builtin_shufflevector((a), (b), (i) & 1, \ - (((i) & 2) >> 1) + 2)) +#define _mm_shuffle_pd(a, b, i) \ + (__builtin_shufflevector((__m128d)(a), (__m128d)(b), (i) & 1, \ + (((i) & 2) >> 1) + 2)) static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_castpd_ps(__m128d in) diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index 4e313b23b3d0..3e82e28c42ed 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -723,7 +723,8 @@ _mm_setcsr(unsigned int i) } #define _mm_shuffle_ps(a, b, mask) \ - (__builtin_shufflevector(a, b, (mask) & 0x3, ((mask) & 0xc) >> 2, \ + (__builtin_shufflevector((__v4sf)a, (__v4sf)b, \ + (mask) & 0x3, ((mask) & 0xc) >> 2, \ (((mask) & 0x30) >> 4) + 4, \ (((mask) & 0xc0) >> 6) + 4)) diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp index 091bc78c2669..bd3b5ee8bf98 100644 --- a/lib/Index/ASTLocation.cpp +++ b/lib/Index/ASTLocation.cpp @@ -69,7 +69,7 @@ SourceRange ASTLocation::getSourceRange() const { case N_NamedRef: return SourceRange(AsNamedRef().Loc, AsNamedRef().Loc); case N_Type: - return AsTypeLoc().getSourceRange(); + return AsTypeLoc().getLocalSourceRange(); } return SourceRange(); diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp index 1354fe6be0d2..6be35ab4a378 100644 --- a/lib/Index/Analyzer.cpp +++ b/lib/Index/Analyzer.cpp @@ -180,7 +180,7 @@ public: if (IsInstanceMethod) return false; - MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + MsgD = Msg->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); break; } @@ -189,7 +189,7 @@ public: if (IsInstanceMethod) return false; - MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); + MsgD = Msg->getSuperType()->getAs<ObjCObjectType>()->getInterface(); break; case ObjCMessageExpr::SuperInstance: @@ -292,12 +292,12 @@ public: case ObjCMessageExpr::Class: CanBeClassMethod = true; - MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + MsgD = Msg->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); break; case ObjCMessageExpr::SuperClass: CanBeClassMethod = true; - MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); + MsgD = Msg->getSuperType()->getAs<ObjCObjectType>()->getInterface(); break; case ObjCMessageExpr::SuperInstance: diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index 4bb15943bb4d..ccd7a126b40c 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -51,7 +51,7 @@ protected: return CheckRange(D->getSourceRange()); } RangePos CheckRange(Stmt *Node) { return CheckRange(Node->getSourceRange()); } - RangePos CheckRange(TypeLoc TL) { return CheckRange(TL.getSourceRange()); } + RangePos CheckRange(TypeLoc TL) { return CheckRange(TL.getLocalSourceRange()); } template <typename T> bool isBeforeLocation(T Node) { @@ -130,7 +130,7 @@ public: ASTLocation VisitFunctionTypeLoc(FunctionTypeLoc TL); ASTLocation VisitArrayTypeLoc(ArrayTypeLoc TL); ASTLocation VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); - ASTLocation VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); + ASTLocation VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL); ASTLocation VisitTypeLoc(TypeLoc TL); }; @@ -454,6 +454,13 @@ ASTLocation TypeLocResolver::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) if (ContainsLocation(TL.getNameLoc())) return ASTLocation(ParentDecl, TL.getIFaceDecl(), TL.getNameLoc()); + return ASTLocation(ParentDecl, TL); +} + +ASTLocation TypeLocResolver::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + assert(ContainsLocation(TL) && + "Should visit only after verifying that loc is in range"); + for (unsigned i = 0; i != TL.getNumProtocols(); ++i) { SourceLocation L = TL.getProtocolLoc(i); RangePos RP = CheckRange(L); @@ -466,24 +473,6 @@ ASTLocation TypeLocResolver::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) return ASTLocation(ParentDecl, TL); } -ASTLocation TypeLocResolver::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - assert(ContainsLocation(TL) && - "Should visit only after verifying that loc is in range"); - - if (TL.hasProtocolsAsWritten()) { - for (unsigned i = 0; i != TL.getNumProtocols(); ++i) { - SourceLocation L = TL.getProtocolLoc(i); - RangePos RP = CheckRange(L); - if (RP == AfterLoc) - break; - if (RP == ContainsLoc) - return ASTLocation(ParentDecl, TL.getProtocol(i), L); - } - } - - return ASTLocation(ParentDecl, TL); -} - ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 74e8d7489e9a..cd153e147b5d 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -1141,7 +1141,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { unsigned char C = getCharAndSize(CurPtr, CharSize); CurPtr += CharSize; if (C == 0 && CurPtr == BufferEnd+1) { - if (!isLexingRawMode()) + if (!isLexingRawMode() && + !PP->isCodeCompletionFile(FileLoc)) Diag(BufferPtr, diag::err_unterminated_block_comment); --CurPtr; @@ -1224,7 +1225,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { Diag(CurPtr-1, diag::warn_nested_block_comment); } } else if (C == 0 && CurPtr == BufferEnd+1) { - if (!isLexingRawMode()) + if (!isLexingRawMode() && !PP->isCodeCompletionFile(FileLoc)) Diag(BufferPtr, diag::err_unterminated_block_comment); // Note: the user probably forgot a */. We could continue immediately // after the /*, but this would involve lexing a lot of what really is the @@ -1358,6 +1359,9 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // Only do the eof -> code_completion translation once. PP->SetCodeCompletionPoint(0, 0, 0); + + // Silence any diagnostics that occur once we hit the code-completion point. + PP->getDiagnostics().setSuppressAllDiagnostics(true); return true; } @@ -1421,6 +1425,7 @@ static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd) { if (RestOfBuffer[Pos-1] != '\r' && RestOfBuffer[Pos-1] != '\n') { RestOfBuffer = RestOfBuffer.substr(Pos+7); + Pos = RestOfBuffer.find(">>>>>>>"); continue; } return RestOfBuffer.data()+Pos; @@ -1450,7 +1455,7 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { // Check to see if there is a >>>>>>> somewhere in the buffer at the start of // a line to terminate this conflict marker. - if (FindConflictEnd(CurPtr+7, BufferEnd)) { + if (FindConflictEnd(CurPtr, BufferEnd)) { // We found a match. We are really in a conflict marker. // Diagnose this, and ignore to the end of line. Diag(CurPtr, diag::err_conflict_marker); diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index f4255822641d..b73f236641c0 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -34,7 +34,7 @@ static int HexDigitValue(char C) { static unsigned ProcessCharEscape(const char *&ThisTokBuf, const char *ThisTokEnd, bool &HadError, SourceLocation Loc, bool IsWide, - Preprocessor &PP) { + Preprocessor &PP, bool Complain) { // Skip the '\' char. ++ThisTokBuf; @@ -54,11 +54,13 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, ResultChar = 8; break; case 'e': - PP.Diag(Loc, diag::ext_nonstandard_escape) << "e"; + if (Complain) + PP.Diag(Loc, diag::ext_nonstandard_escape) << "e"; ResultChar = 27; break; case 'E': - PP.Diag(Loc, diag::ext_nonstandard_escape) << "E"; + if (Complain) + PP.Diag(Loc, diag::ext_nonstandard_escape) << "E"; ResultChar = 27; break; case 'f': @@ -79,7 +81,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, case 'x': { // Hex escape. ResultChar = 0; if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) { - PP.Diag(Loc, diag::err_hex_escape_no_digits); + if (Complain) + PP.Diag(Loc, diag::err_hex_escape_no_digits); HadError = 1; break; } @@ -106,7 +109,7 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, } // Check for overflow. - if (Overflow) // Too many digits to fit in + if (Overflow && Complain) // Too many digits to fit in PP.Diag(Loc, diag::warn_hex_escape_too_large); break; } @@ -132,7 +135,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, : PP.getTargetInfo().getCharWidth(); if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { - PP.Diag(Loc, diag::warn_octal_escape_too_large); + if (Complain) + PP.Diag(Loc, diag::warn_octal_escape_too_large); ResultChar &= ~0U >> (32-CharWidth); } break; @@ -141,10 +145,14 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, // Otherwise, these are not valid escapes. case '(': case '{': case '[': case '%': // GCC accepts these as extensions. We warn about them as such though. - PP.Diag(Loc, diag::ext_nonstandard_escape) - << std::string()+(char)ResultChar; + if (Complain) + PP.Diag(Loc, diag::ext_nonstandard_escape) + << std::string()+(char)ResultChar; break; default: + if (!Complain) + break; + if (isgraph(ThisTokBuf[0])) PP.Diag(Loc, diag::ext_unknown_escape) << std::string()+(char)ResultChar; else @@ -161,7 +169,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, /// we will likely rework our support for UCN's. static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, char *&ResultBuf, bool &HadError, - SourceLocation Loc, bool IsWide, Preprocessor &PP) + SourceLocation Loc, bool IsWide, Preprocessor &PP, + bool Complain) { // FIXME: Add a warning - UCN's are only valid in C++ & C99. // FIXME: Handle wide strings. @@ -173,7 +182,8 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, ThisTokBuf += 2; if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) { - PP.Diag(Loc, diag::err_ucn_escape_no_digits); + if (Complain) + PP.Diag(Loc, diag::err_ucn_escape_no_digits); HadError = 1; return; } @@ -189,8 +199,9 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, } // If we didn't consume the proper number of digits, there is a problem. if (UcnLen) { - PP.Diag(PP.AdvanceToTokenCharacter(Loc, ThisTokBuf-ThisTokBegin), - diag::err_ucn_escape_incomplete); + if (Complain) + PP.Diag(PP.AdvanceToTokenCharacter(Loc, ThisTokBuf-ThisTokBegin), + diag::err_ucn_escape_incomplete); HadError = 1; return; } @@ -199,7 +210,8 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, (UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60 )) // $, @, ` || (UcnVal >= 0xD800 && UcnVal <= 0xDFFF) || (UcnVal > 0x10FFFF)) /* the maximum legal UTF32 value */ { - PP.Diag(Loc, diag::err_ucn_escape_invalid); + if (Complain) + PP.Diag(Loc, diag::err_ucn_escape_invalid); HadError = 1; return; } @@ -660,7 +672,8 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, if (begin[0] != '\\') // If this is a normal character, consume it. ResultChar = *begin++; else // Otherwise, this is an escape character. - ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP); + ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP, + /*Complain=*/true); // If this is a multi-character constant (e.g. 'abc'), handle it. These are // implementation defined (C99 6.4.4.4p10). @@ -746,7 +759,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, /// StringLiteralParser:: StringLiteralParser(const Token *StringToks, unsigned NumStringToks, - Preprocessor &pp) : PP(pp) { + Preprocessor &pp, bool Complain) : PP(pp) { // Scan all of the string portions, remember the max individual token length, // computing a bound on the concatenated string length, and see whether any // piece is a wide-string. If any of the string portions is a wide-string @@ -871,13 +884,14 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks, // Is this a Universal Character Name escape? if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') { ProcessUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr, - hadError, StringToks[i].getLocation(), ThisIsWide, PP); + hadError, StringToks[i].getLocation(), ThisIsWide, PP, + Complain); continue; } // Otherwise, this is a non-UCN escape character. Process it. unsigned ResultChar = ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError, StringToks[i].getLocation(), - ThisIsWide, PP); + ThisIsWide, PP, Complain); // Note: our internal rep of wide char tokens is always little-endian. *ResultPtr++ = ResultChar & 0xFF; @@ -893,7 +907,7 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks, ResultBuf[0] = ResultPtr-&ResultBuf[0]-1; // Verify that pascal strings aren't too large. - if (GetStringLength() > 256) { + if (GetStringLength() > 256 && Complain) { PP.Diag(StringToks[0].getLocation(), diag::err_pascal_string_too_long) << SourceRange(StringToks[0].getLocation(), StringToks[NumStringToks-1].getLocation()); @@ -909,7 +923,8 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks, /// advancing over escape sequences in the string. unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok, unsigned ByteNo, - Preprocessor &PP) { + Preprocessor &PP, + bool Complain) { // Get the spelling of the token. llvm::SmallString<16> SpellingBuffer; SpellingBuffer.resize(Tok.getLength()); @@ -945,7 +960,7 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok, // Otherwise, this is an escape character. Advance over it. bool HadError = false; ProcessCharEscape(SpellingPtr, SpellingEnd, HadError, - Tok.getLocation(), false, PP); + Tok.getLocation(), false, PP, Complain); assert(!HadError && "This method isn't valid on erroneous strings"); --ByteNo; } diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index bae2a09a9882..1ebff22e4403 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -84,6 +84,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("fastcall", AT_fastcall) .Case("ibaction", AT_IBAction) .Case("iboutlet", AT_IBOutlet) + .Case("iboutletcollection", AT_IBOutletCollection) .Case("noreturn", AT_noreturn) .Case("noinline", AT_noinline) .Case("override", AT_override) @@ -119,5 +120,10 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("cf_returns_retained", AT_cf_returns_retained) .Case("reqd_work_group_size", AT_reqd_wg_size) .Case("no_instrument_function", AT_no_instrument_function) + .Case("thiscall", AT_thiscall) + .Case("__cdecl", AT_cdecl) + .Case("__stdcall", AT_stdcall) + .Case("__fastcall", AT_fastcall) + .Case("__thiscall", AT_thiscall) .Default(UnknownAttribute); } diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 5a0376781175..b7205160c177 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -194,7 +194,9 @@ MinimalAction::isTemplateName(Scope *S, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringScope, - TemplateTy &TemplateDecl) { + TemplateTy &TemplateDecl, + bool &MemberOfUnknownSpecialization) { + MemberOfUnknownSpecialization = false; return TNK_Non_template; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 91050e0a4cf9..3e7d4a13c5df 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -277,8 +277,8 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { // Treat these like attributes // FIXME: Allow Sema to distinguish between these and real attributes! while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || - Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) || - Tok.is(tok::kw___w64)) { + Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || + Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) @@ -364,7 +364,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { if (RequireSemi) ConsumeToken(); - DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS_none, + DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -838,7 +839,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, CCC = Action::CCC_ObjCImplementation; Actions.CodeCompleteOrdinaryName(CurScope, CCC); - ConsumeToken(); + ConsumeCodeCompletionToken(); } DS.SetRangeStart(Tok.getLocation()); @@ -1143,6 +1144,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: + case tok::kw___thiscall: DS.AddAttributes(ParseMicrosoftTypeAttributes()); continue; @@ -1622,6 +1624,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: + case tok::kw___thiscall: DS.AddAttributes(ParseMicrosoftTypeAttributes()); return true; @@ -1674,7 +1677,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // If there are no declarators, this is a free-standing declaration // specifier. Let the actions module cope with it. if (Tok.is(tok::semi)) { - Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + Actions.ParsedFreeStandingDeclSpec(CurScope, AS_none, DS); return; } @@ -1867,7 +1870,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.is(tok::code_completion)) { // Code completion for an enum name. Actions.CodeCompleteTag(CurScope, DeclSpec::TST_enum); - ConsumeToken(); + ConsumeCodeCompletionToken(); } llvm::OwningPtr<AttributeList> Attr; @@ -1875,7 +1878,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.is(tok::kw___attribute)) Attr.reset(ParseGNUAttributes()); - CXXScopeSpec SS; + CXXScopeSpec &SS = DS.getTypeSpecScope(); if (getLang().CPlusPlus) { if (ParseOptionalCXXScopeSpecifier(SS, 0, false)) return; @@ -2198,6 +2201,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: + case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: return true; @@ -2304,6 +2308,7 @@ bool Parser::isDeclarationSpecifier() { case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: + case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: case tok::kw___forceinline: @@ -2401,6 +2406,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed, case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: + case tok::kw___thiscall: if (GNUAttributesAllowed) { DS.AddAttributes(ParseMicrosoftTypeAttributes()); continue; @@ -2785,8 +2791,8 @@ void Parser::ParseParenDeclarator(Declarator &D) { } // Eat any Microsoft extensions. if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || - Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___w64) || - Tok.is(tok::kw___ptr64)) { + Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) || + Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64)) { AttrList.reset(ParseMicrosoftTypeAttributes(AttrList.take())); } @@ -2937,9 +2943,33 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, Diag(Tok, diag::err_argument_required_after_attribute); delete AttrList; } + // Identifier list. Note that '(' identifier-list ')' is only allowed for - // normal declarators, not for abstract-declarators. - return ParseFunctionDeclaratorIdentifierList(LParenLoc, D); + // normal declarators, not for abstract-declarators. Get the first + // identifier. + Token FirstTok = Tok; + ConsumeToken(); // eat the first identifier. + + // Identifier lists follow a really simple grammar: the identifiers can + // be followed *only* by a ", moreidentifiers" or ")". However, K&R + // identifier lists are really rare in the brave new modern world, and it + // is very common for someone to typo a type in a non-k&r style list. If + // we are presented with something like: "void foo(intptr x, float y)", + // we don't want to start parsing the function declarator as though it is + // a K&R style declarator just because intptr is an invalid type. + // + // To handle this, we check to see if the token after the first identifier + // is a "," or ")". Only if so, do we parse it as an identifier list. + if (Tok.is(tok::comma) || Tok.is(tok::r_paren)) + return ParseFunctionDeclaratorIdentifierList(LParenLoc, + FirstTok.getIdentifierInfo(), + FirstTok.getLocation(), D); + + // If we get here, the code is invalid. Push the first identifier back + // into the token stream and parse the first argument as an (invalid) + // normal argument declarator. + PP.EnterToken(Tok); + Tok = FirstTok; } } @@ -3122,13 +3152,16 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator /// we found a K&R-style identifier list instead of a type argument list. The -/// current token is known to be the first identifier in the list. +/// first identifier has already been consumed, and the current token is the +/// token right after it. /// /// identifier-list: [C99 6.7.5] /// identifier /// identifier-list ',' identifier /// void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, + IdentifierInfo *FirstIdent, + SourceLocation FirstIdentLoc, Declarator &D) { // Build up an array of information about the parsed arguments. llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo; @@ -3139,17 +3172,14 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, // to be abstract. In abstract-declarators, identifier lists are not valid: // diagnose this. if (!D.getIdentifier()) - Diag(Tok, diag::ext_ident_list_in_param); + Diag(FirstIdentLoc, diag::ext_ident_list_in_param); - // Tok is known to be the first identifier in the list. Remember this - // identifier in ParamInfo. - ParamsSoFar.insert(Tok.getIdentifierInfo()); - ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(), - Tok.getLocation(), + // The first identifier was already read, and is known to be the first + // identifier in the list. Remember this identifier in ParamInfo. + ParamsSoFar.insert(FirstIdent); + ParamInfo.push_back(DeclaratorChunk::ParamInfo(FirstIdent, FirstIdentLoc, DeclPtrTy())); - ConsumeToken(); // eat the first identifier. - while (Tok.is(tok::comma)) { // Eat the comma. ConsumeToken(); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 015ac5b5dddd..479c04c37d7a 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -50,7 +50,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteNamespaceDecl(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); } SourceLocation IdentLoc; @@ -87,6 +87,14 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, SourceLocation LBrace = ConsumeBrace(); + if (CurScope->isClassScope() || CurScope->isTemplateParamScope() || + CurScope->isInObjcMethodScope() || CurScope->getBlockParent() || + CurScope->getFnParent()) { + Diag(LBrace, diag::err_namespace_nonnamespace_scope); + SkipUntil(tok::r_brace, false); + return DeclPtrTy(); + } + // Enter a scope for the namespace. ParseScope NamespaceScope(this, Scope::DeclScope); @@ -128,7 +136,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteNamespaceAliasDecl(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); } CXXScopeSpec SS; @@ -223,7 +231,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteUsing(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.is(tok::kw_namespace)) @@ -260,7 +268,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteUsingDirective(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); } CXXScopeSpec SS; @@ -602,7 +610,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.is(tok::code_completion)) { // Code completion for a struct, class, or union name. Actions.CodeCompleteTag(CurScope, TagType); - ConsumeToken(); + ConsumeCodeCompletionToken(); } AttributeList *AttrList = 0; @@ -973,6 +981,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, case tok::kw_typedef: // struct foo {...} typedef x; case tok::kw_register: // struct foo {...} register x; case tok::kw_auto: // struct foo {...} auto x; + case tok::kw_mutable: // struct foo {...} mutable x; // As shown above, type qualifiers and storage class specifiers absolutely // can occur after class specifiers according to the grammar. However, // almost noone actually writes code like this. If we see one of these, @@ -1298,7 +1307,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::semi)) { ConsumeToken(); - Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS); return; } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index b9e632a1846e..b036e568f8bb 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -222,7 +222,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { Parser::OwningExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.is(tok::kw_throw)) @@ -315,8 +315,29 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { // Eat the colon. ColonLoc = ConsumeToken(); } else { + // Otherwise, we're missing a ':'. Assume that this was a typo that the + // user forgot. If we're not in a macro instantion, we can suggest a + // fixit hint. If there were two spaces before the current token, + // suggest inserting the colon in between them, otherwise insert ": ". + SourceLocation FILoc = Tok.getLocation(); + const char *FIText = ": "; + if (FILoc.isFileID()) { + const SourceManager &SM = PP.getSourceManager(); + bool IsInvalid = false; + const char *SourcePtr = + SM.getCharacterData(FILoc.getFileLocWithOffset(-1), &IsInvalid); + if (!IsInvalid && *SourcePtr == ' ') { + SourcePtr = + SM.getCharacterData(FILoc.getFileLocWithOffset(-2), &IsInvalid); + if (!IsInvalid && *SourcePtr == ' ') { + FILoc = FILoc.getFileLocWithOffset(-1); + FIText = ":"; + } + } + } + Diag(Tok, diag::err_expected_colon) - << FixItHint::CreateInsertion(Tok.getLocation(), ": "); + << FixItHint::CreateInsertion(FILoc, FIText); Diag(OpToken, diag::note_matching) << "?"; ColonLoc = Tok.getLocation(); } @@ -885,7 +906,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression()); case tok::code_completion: Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); - ConsumeToken(); + ConsumeCodeCompletionToken(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); case tok::l_square: @@ -954,7 +975,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCall(CurScope, LHS.get(), 0, 0); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::r_paren)) { @@ -1008,7 +1029,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { Actions.CodeCompleteMemberReferenceExpr(CurScope, LHS.get(), OpLoc, OpKind == tok::arrow); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (MayBePseudoDestructor) { @@ -1541,7 +1562,7 @@ bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs, if (Tok.is(tok::code_completion)) { if (Completer) (Actions.*Completer)(CurScope, Data, Exprs.data(), Exprs.size()); - ConsumeToken(); + ConsumeCodeCompletionToken(); } OwningExprResult Expr(ParseAssignmentExpression()); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 146762b83ad5..46f1d94cf2c1 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -110,7 +110,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // Code completion for a nested-name-specifier, where the code // code completion token follows the '::'. Actions.CodeCompleteQualifiedId(CurScope, SS, EnteringContext); - ConsumeToken(); + ConsumeCodeCompletionToken(); } } @@ -289,11 +289,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, EnteringContext, - Template)) { + Template, + MemberOfUnknownSpecialization)) { // We have found a template name, so annotate this this token // with a template-id annotation. We do not permit the // template-id to be translated into a type annotation, @@ -305,6 +307,31 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, SourceLocation(), false)) return true; continue; + } + + if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && + IsTemplateArgumentList(1)) { + // We have something like t::getAs<T>, where getAs is a + // member of an unknown specialization. However, this will only + // parse correctly as a template, so suggest the keyword 'template' + // before 'getAs' and treat this as a dependent template name. + Diag(Tok.getLocation(), diag::err_missing_dependent_template_keyword) + << II.getName() + << FixItHint::CreateInsertion(Tok.getLocation(), "template "); + + Template = Actions.ActOnDependentTemplateName(Tok.getLocation(), SS, + TemplateName, ObjectType, + EnteringContext); + if (!Template.get()) + return true; + + // Consume the identifier. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, &SS, + TemplateName, SourceLocation(), false)) + return true; + + continue; } } @@ -576,7 +603,8 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, // it as such. if (Tok.is(tok::less) && ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType, - SecondTypeName, /*AssumeTemplateName=*/true)) + SecondTypeName, /*AssumeTemplateName=*/true, + /*TemplateKWLoc*/SourceLocation())) return ExprError(); return Actions.ActOnPseudoDestructorExpr(CurScope, move(Base), OpLoc, OpKind, @@ -688,17 +716,33 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// \param DeclResult if the condition was parsed as a declaration, the /// parsed declaration. /// +/// \param Loc The location of the start of the statement that requires this +/// condition, e.g., the "for" in a for loop. +/// +/// \param ConvertToBoolean Whether the condition expression should be +/// converted to a boolean value. +/// /// \returns true if there was a parsing, false otherwise. bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, - DeclPtrTy &DeclResult) { + DeclPtrTy &DeclResult, + SourceLocation Loc, + bool ConvertToBoolean) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Condition); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (!isCXXConditionDeclaration()) { + // Parse the expression. ExprResult = ParseExpression(); // expression DeclResult = DeclPtrTy(); + if (ExprResult.isInvalid()) + return true; + + // If required, convert to a boolean value. + if (ConvertToBoolean) + ExprResult + = Actions.ActOnBooleanCondition(CurScope, Loc, move(ExprResult)); return ExprResult.isInvalid(); } @@ -746,6 +790,9 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, Diag(Tok, diag::err_expected_equal_after_declarator); } + // FIXME: Build a reference to this declaration? Convert it to bool? + // (This is currently handled by Sema). + return false; } @@ -952,8 +999,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, bool EnteringContext, TypeTy *ObjectType, UnqualifiedId &Id, - bool AssumeTemplateId) { - assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id"); + bool AssumeTemplateId, + SourceLocation TemplateKWLoc) { + assert((AssumeTemplateId || Tok.is(tok::less)) && + "Expected '<' to finish parsing a template-id"); TemplateTy Template; TemplateNameKind TNK = TNK_Non_template; @@ -962,30 +1011,63 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: if (AssumeTemplateId) { - Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, + Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, Id, ObjectType, EnteringContext); TNK = TNK_Dependent_template_name; if (!Template.get()) return true; - } else + } else { + bool MemberOfUnknownSpecialization; TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, - EnteringContext, Template); + EnteringContext, Template, + MemberOfUnknownSpecialization); + + if (TNK == TNK_Non_template && MemberOfUnknownSpecialization && + ObjectType && IsTemplateArgumentList()) { + // We have something like t->getAs<T>(), where getAs is a + // member of an unknown specialization. However, this will only + // parse correctly as a template, so suggest the keyword 'template' + // before 'getAs' and treat this as a dependent template name. + std::string Name; + if (Id.getKind() == UnqualifiedId::IK_Identifier) + Name = Id.Identifier->getName(); + else { + Name = "operator "; + if (Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) + Name += getOperatorSpelling(Id.OperatorFunctionId.Operator); + else + Name += Id.Identifier->getName(); + } + Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword) + << Name + << FixItHint::CreateInsertion(Id.StartLocation, "template "); + Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, + Id, ObjectType, + EnteringContext); + TNK = TNK_Dependent_template_name; + if (!Template.get()) + return true; + } + } break; case UnqualifiedId::IK_ConstructorName: { UnqualifiedId TemplateName; + bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, - EnteringContext, Template); + EnteringContext, Template, + MemberOfUnknownSpecialization); break; } case UnqualifiedId::IK_DestructorName: { UnqualifiedId TemplateName; + bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { - Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, + Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName, ObjectType, EnteringContext); TNK = TNK_Dependent_template_name; @@ -993,7 +1075,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, return true; } else { TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, - EnteringContext, Template); + EnteringContext, Template, + MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && Id.DestructorName == 0) { Diag(NameLoc, diag::err_destructor_template_id) @@ -1014,7 +1097,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, + if (Tok.is(tok::less) && + ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, &SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) @@ -1190,7 +1274,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, Actions.CodeCompleteOperatorName(CurScope); // Consume the operator token. - ConsumeToken(); + ConsumeCodeCompletionToken(); // Don't try to parse any further. return true; @@ -1293,6 +1377,17 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowConstructorName, TypeTy *ObjectType, UnqualifiedId &Result) { + + // Handle 'A::template B'. This is for template-ids which have not + // already been annotated by ParseOptionalCXXScopeSpecifier(). + bool TemplateSpecified = false; + SourceLocation TemplateKWLoc; + if (getLang().CPlusPlus && Tok.is(tok::kw_template) && + (ObjectType || SS.isSet())) { + TemplateSpecified = true; + TemplateKWLoc = ConsumeToken(); + } + // unqualified-id: // identifier // template-id (when it hasn't already been annotated) @@ -1320,9 +1415,10 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, } // If the next token is a '<', we may have a template. - if (Tok.is(tok::less)) + if (TemplateSpecified || Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext, - ObjectType, Result); + ObjectType, Result, + TemplateSpecified, TemplateKWLoc); return false; } @@ -1383,10 +1479,11 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // operator-function-id < template-argument-list[opt] > if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId || Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) && - Tok.is(tok::less)) + (TemplateSpecified || Tok.is(tok::less))) return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), EnteringContext, ObjectType, - Result); + Result, + TemplateSpecified, TemplateKWLoc); return false; } @@ -1411,10 +1508,11 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, IdentifierInfo *ClassName = Tok.getIdentifierInfo(); SourceLocation ClassNameLoc = ConsumeToken(); - if (Tok.is(tok::less)) { + if (TemplateSpecified || Tok.is(tok::less)) { Result.setDestructorName(TildeLoc, 0, ClassNameLoc); return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc, - EnteringContext, ObjectType, Result); + EnteringContext, ObjectType, Result, + TemplateSpecified, TemplateKWLoc); } // Note that this is a destructor name. diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 7b1ecf6437dc..9cfe73456a5f 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -32,7 +32,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtDirectives() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, false); - ConsumeToken(); + ConsumeCodeCompletionToken(); } switch (Tok.getObjCKeywordID()) { @@ -131,7 +131,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( // Code completion after '@interface'. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCInterfaceDecl(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::identifier)) { @@ -149,7 +149,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( IdentifierInfo *categoryId = 0; if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId, nameLoc); - ConsumeToken(); + ConsumeCodeCompletionToken(); } // For ObjC2, the category name is optional (not an error). @@ -204,7 +204,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( // Code completion of superclass names. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCSuperclass(CurScope, nameId, nameLoc); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::identifier)) { @@ -350,7 +350,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, Actions.CodeCompleteOrdinaryName(CurScope, ObjCImpDecl? Action::CCC_ObjCImplementation : Action::CCC_ObjCInterface); - ConsumeToken(); + ConsumeCodeCompletionToken(); } // If we don't have an @ directive, parse it as a function definition. @@ -371,7 +371,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, SourceLocation AtLoc = ConsumeToken(); // the "@" if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true); - ConsumeToken(); + ConsumeCodeCompletionToken(); break; } @@ -438,7 +438,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // EOF. In the former case, eat the @end. In the later case, emit an error. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true); - ConsumeToken(); + ConsumeCodeCompletionToken(); } else if (Tok.isObjCAtKeyword(tok::objc_end)) ConsumeToken(); // the "end" identifier else @@ -446,7 +446,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // Insert collected methods declarations into the @interface object. // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit. - Actions.ActOnAtEnd(AtEnd, interfaceDecl, + Actions.ActOnAtEnd(CurScope, AtEnd, interfaceDecl, allMethods.data(), allMethods.size(), allProperties.data(), allProperties.size(), allTUVariables.data(), allTUVariables.size()); @@ -477,7 +477,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl, while (1) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPropertyFlags(CurScope, DS); - ConsumeToken(); + ConsumeCodeCompletionToken(); } const IdentifierInfo *II = Tok.getIdentifierInfo(); @@ -514,7 +514,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl, else Actions.CodeCompleteObjCPropertyGetter(CurScope, ClassDecl, Methods, NumMethods); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::identifier)) { @@ -782,7 +782,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, /*ReturnType=*/0, IDecl); - ConsumeToken(); + ConsumeCodeCompletionToken(); } // Parse the return type if present. @@ -799,7 +799,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, ReturnType, IDecl); - ConsumeToken(); + ConsumeCodeCompletionToken(); } // Now parse the selector. @@ -945,7 +945,7 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(), ProtocolIdents.size()); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::identifier)) { @@ -1026,7 +1026,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtVisibility(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); } switch (Tok.getObjCKeywordID()) { @@ -1046,7 +1046,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_ObjCInstanceVariableList); - ConsumeToken(); + ConsumeCodeCompletionToken(); } struct ObjCIvarCallback : FieldCallback { @@ -1117,7 +1117,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCProtocolDecl(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::identifier)) { @@ -1203,7 +1203,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( // Code completion after '@implementation'. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationDecl(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::identifier)) { @@ -1222,7 +1222,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId, nameLoc); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.is(tok::identifier)) { @@ -1277,7 +1277,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { DeclPtrTy Result = ObjCImpDecl; ConsumeToken(); // the "end" identifier if (ObjCImpDecl) { - Actions.ActOnAtEnd(atEnd, ObjCImpDecl); + Actions.ActOnAtEnd(CurScope, atEnd, ObjCImpDecl); ObjCImpDecl = DeclPtrTy(); PendingObjCImpDecl.pop_back(); } @@ -1292,7 +1292,7 @@ Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() { if (PendingObjCImpDecl.empty()) return Actions.ConvertDeclToDeclGroup(DeclPtrTy()); DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val(); - Actions.ActOnAtEnd(SourceRange(), ImpDecl); + Actions.ActOnAtEnd(CurScope, SourceRange(), ImpDecl); return Actions.ConvertDeclToDeclGroup(ImpDecl); } @@ -1342,7 +1342,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { while (true) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::identifier)) { @@ -1361,7 +1361,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPropertySynthesizeIvar(CurScope, propertyId, ObjCImpDecl); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::identifier)) { @@ -1371,7 +1371,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { propertyIvar = Tok.getIdentifierInfo(); ConsumeToken(); // consume ivar-name } - Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, true, ObjCImpDecl, + Actions.ActOnPropertyImplDecl(CurScope, atLoc, propertyLoc, true, ObjCImpDecl, propertyId, propertyIvar); if (Tok.isNot(tok::comma)) break; @@ -1400,7 +1400,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { while (true) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl); - ConsumeToken(); + ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::identifier)) { @@ -1411,7 +1411,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { IdentifierInfo *propertyId = Tok.getIdentifierInfo(); SourceLocation propertyLoc = ConsumeToken(); // consume property name - Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl, + Actions.ActOnPropertyImplDecl(CurScope, atLoc, propertyLoc, false, ObjCImpDecl, propertyId, 0); if (Tok.isNot(tok::comma)) @@ -1654,7 +1654,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtStatement(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); return StmtError(); } @@ -1685,7 +1685,7 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { switch (Tok.getKind()) { case tok::code_completion: Actions.CodeCompleteObjCAtExpression(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); return ExprError(); case tok::string_literal: // primary-expression: string-literal @@ -1925,7 +1925,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, else Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(), 0, 0); - ConsumeToken(); + ConsumeCodeCompletionToken(); } // Parse objc-selector @@ -1979,7 +1979,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(), KeyIdents.data(), KeyIdents.size()); - ConsumeToken(); + ConsumeCodeCompletionToken(); } // Check for another keyword selector. diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 812d8e2af901..c4e4a525e560 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -23,7 +23,6 @@ using namespace clang; // pack '(' 'show' ')' // pack '(' ('push' | 'pop') [',' identifier] [, integer] ')' void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { - // FIXME: Should we be expanding macros here? My guess is no. SourceLocation PackLoc = PackTok.getLocation(); Token Tok; @@ -100,17 +99,67 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { return; } + SourceLocation RParenLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::eom)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack"; return; } - SourceLocation RParenLoc = Tok.getLocation(); Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc, LParenLoc, RParenLoc); } +// #pragma 'options' 'align' '=' {'natural', 'mac68k', 'power', 'reset'} +void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) { + SourceLocation OptionsLoc = OptionsTok.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier) || !Tok.getIdentifierInfo()->isStr("align")) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align); + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::equal)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_equal); + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "options"; + return; + } + + Action::PragmaOptionsAlignKind Kind = Action::POAK_Natural; + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II->isStr("natural")) + Kind = Action::POAK_Natural; + else if (II->isStr("power")) + Kind = Action::POAK_Power; + else if (II->isStr("mac68k")) + Kind = Action::POAK_Mac68k; + else if (II->isStr("reset")) + Kind = Action::POAK_Reset; + else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_options_invalid_option); + return; + } + + SourceLocation KindLoc = Tok.getLocation(); + PP.Lex(Tok); + if (Tok.isNot(tok::eom)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "options"; + return; + } + + Actions.ActOnPragmaOptionsAlign(Kind, OptionsLoc, KindLoc); +} + // #pragma unused(identifier) void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) { // FIXME: Should we be expanding macros here? My guess is no. diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index db385c6371e3..d9d06a1dc6e6 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -20,6 +20,15 @@ namespace clang { class Action; class Parser; +class PragmaOptionsHandler : public PragmaHandler { + Action &Actions; +public: + PragmaOptionsHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N), + Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); +}; + class PragmaPackHandler : public PragmaHandler { Action &Actions; public: diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 9b2227002f1b..98c005837e7c 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -283,7 +283,7 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCase(CurScope); - ConsumeToken(); + ConsumeCodeCompletionToken(); } /// We don't want to treat 'case x : y' as a potential typo for 'case x::y'. @@ -536,15 +536,23 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { /// successfully parsed. Note that a successful parse can still have semantic /// errors in the condition. bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult, - DeclPtrTy &DeclResult) { + DeclPtrTy &DeclResult, + SourceLocation Loc, + bool ConvertToBoolean) { bool ParseError = false; SourceLocation LParenLoc = ConsumeParen(); if (getLang().CPlusPlus) - ParseError = ParseCXXCondition(ExprResult, DeclResult); + ParseError = ParseCXXCondition(ExprResult, DeclResult, Loc, + ConvertToBoolean); else { ExprResult = ParseExpression(); DeclResult = DeclPtrTy(); + + // If required, convert to a boolean value. + if (!ExprResult.isInvalid() && ConvertToBoolean) + ExprResult + = Actions.ActOnBooleanCondition(CurScope, Loc, move(ExprResult)); } // If the parser was confused by the condition and we don't have a ')', try to @@ -603,7 +611,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { // Parse the condition. OwningExprResult CondExp(Actions); DeclPtrTy CondVar; - if (ParseParenExprOrCondition(CondExp, CondVar)) + if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true)) return StmtError(); FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp)); @@ -735,13 +743,25 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { // Parse the condition. OwningExprResult Cond(Actions); DeclPtrTy CondVar; - if (ParseParenExprOrCondition(Cond, CondVar)) + if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false)) return StmtError(); - FullExprArg FullCond(Actions.MakeFullExpr(Cond)); + OwningStmtResult Switch + = Actions.ActOnStartOfSwitchStmt(SwitchLoc, move(Cond), CondVar); + + if (Switch.isInvalid()) { + // Skip the switch body. + // FIXME: This is not optimal recovery, but parsing the body is more + // dangerous due to the presence of case and default statements, which + // will have no place to connect back with the switch. + if (Tok.is(tok::l_brace)) { + ConsumeBrace(); + SkipUntil(tok::r_brace, false, false); + } else + SkipUntil(tok::semi); + return move(Switch); + } - OwningStmtResult Switch = Actions.ActOnStartOfSwitchStmt(FullCond, CondVar); - // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. @@ -763,11 +783,6 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { InnerScope.Exit(); SwitchScope.Exit(); - if (Cond.isInvalid() && !CondVar.get()) { - Actions.ActOnSwitchBodyError(SwitchLoc, move(Switch), move(Body)); - return StmtError(); - } - if (Body.isInvalid()) // FIXME: Remove the case statement list from the Switch statement. Body = Actions.ActOnNullStmt(Tok.getLocation()); @@ -818,7 +833,7 @@ Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) { // Parse the condition. OwningExprResult Cond(Actions); DeclPtrTy CondVar; - if (ParseParenExprOrCondition(Cond, CondVar)) + if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true)) return StmtError(); FullExprArg FullCond(Actions.MakeFullExpr(Cond)); @@ -975,14 +990,17 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { bool ForEach = false; OwningStmtResult FirstPart(Actions); - OwningExprResult SecondPart(Actions), ThirdPart(Actions); + bool SecondPartIsInvalid = false; + FullExprArg SecondPart(Actions); + OwningExprResult Collection(Actions); + FullExprArg ThirdPart(Actions); DeclPtrTy SecondVar; if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(CurScope, C99orCXXorObjC? Action::CCC_ForInit : Action::CCC_Expression); - ConsumeToken(); + ConsumeCodeCompletionToken(); } // Parse the first part of the for specifier. @@ -1009,7 +1027,7 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { Actions.ActOnForEachDeclStmt(DG); // ObjC: for (id x in expr) ConsumeToken(); // consume 'in' - SecondPart = ParseExpression(); + Collection = ParseExpression(); } else { Diag(Tok, diag::err_expected_semi_for); SkipUntil(tok::semi); @@ -1025,35 +1043,44 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { ConsumeToken(); // consume 'in' - SecondPart = ParseExpression(); + Collection = ParseExpression(); } else { if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for); SkipUntil(tok::semi); } } if (!ForEach) { - assert(!SecondPart.get() && "Shouldn't have a second expression yet."); + assert(!SecondPart->get() && "Shouldn't have a second expression yet."); // Parse the second part of the for specifier. if (Tok.is(tok::semi)) { // for (...;; // no second part. } else { + OwningExprResult Second(Actions); if (getLang().CPlusPlus) - ParseCXXCondition(SecondPart, SecondVar); - else - SecondPart = ParseExpression(); + ParseCXXCondition(Second, SecondVar, ForLoc, true); + else { + Second = ParseExpression(); + if (!Second.isInvalid()) + Second = Actions.ActOnBooleanCondition(CurScope, ForLoc, + move(Second)); + } + SecondPartIsInvalid = Second.isInvalid(); + SecondPart = Actions.MakeFullExpr(Second); } if (Tok.is(tok::semi)) { ConsumeToken(); } else { - if (!SecondPart.isInvalid() || SecondVar.get()) + if (!SecondPartIsInvalid || SecondVar.get()) Diag(Tok, diag::err_expected_semi_for); SkipUntil(tok::semi); } // Parse the third part of the for specifier. - if (Tok.isNot(tok::r_paren)) // for (...;...;) - ThirdPart = ParseExpression(); + if (Tok.isNot(tok::r_paren)) { // for (...;...;) + OwningExprResult Third = ParseExpression(); + ThirdPart = Actions.MakeFullExpr(Third); + } } // Match the ')'. SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); @@ -1085,15 +1112,14 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { return StmtError(); if (!ForEach) - return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart), - Actions.MakeFullExpr(SecondPart), SecondVar, - Actions.MakeFullExpr(ThirdPart), RParenLoc, - move(Body)); - - return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, - move(FirstPart), - move(SecondPart), - RParenLoc, move(Body)); + return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart), SecondPart, + SecondVar, ThirdPart, RParenLoc, move(Body)); + + // FIXME: It isn't clear how to communicate the late destruction of + // C++ temporaries used to create the collection. + return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, move(FirstPart), + move(Collection), RParenLoc, + move(Body)); } /// ParseGotoStatement diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index ff6995340151..c87ddad4e9b3 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -201,7 +201,7 @@ Parser::ParseSingleDeclarationAfterTemplate( if (Tok.is(tok::semi)) { DeclEnd = ConsumeToken(); - DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS); DS.complete(Decl); return Decl; } @@ -902,10 +902,12 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { ConsumeToken(); // the identifier if (isEndOfTemplateArgument(Tok)) { + bool MemberOfUnknownSpecialization; TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, Name, /*ObjectType=*/0, /*EnteringContext=*/false, - Template); + Template, + MemberOfUnknownSpecialization); if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { // We have an id-expression that refers to a class template or // (C++0x) template alias. @@ -966,6 +968,37 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { ExprArg.release(), Loc); } +/// \brief Determine whether the current tokens can only be parsed as a +/// template argument list (starting with the '<') and never as a '<' +/// expression. +bool Parser::IsTemplateArgumentList(unsigned Skip) { + struct AlwaysRevertAction : TentativeParsingAction { + AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { } + ~AlwaysRevertAction() { Revert(); } + } Tentative(*this); + + while (Skip) { + ConsumeToken(); + --Skip; + } + + // '<' + if (!Tok.is(tok::less)) + return false; + ConsumeToken(); + + // An empty template argument list. + if (Tok.is(tok::greater)) + return true; + + // See whether we have declaration specifiers, which indicate a type. + while (isCXXDeclarationSpecifier() == TPResult::True()) + ConsumeToken(); + + // If we have a '>' or a ',' then this is a template argument list. + return Tok.is(tok::greater) || Tok.is(tok::comma); +} + /// ParseTemplateArgumentList - Parse a C++ template-argument-list /// (C++ [temp.names]). Returns true if there was an error. /// diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index a6c6d3f94535..5e64e6162b73 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -753,6 +753,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: + case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: case tok::kw___forceinline: diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 6dbb99e395f9..296897080d0f 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -33,6 +33,11 @@ Parser::Parser(Preprocessor &pp, Action &actions) // Add #pragma handlers. These are removed and destroyed in the // destructor. + OptionsHandler.reset(new + PragmaOptionsHandler(&PP.getIdentifierTable().get("options"), + actions)); + PP.AddPragmaHandler(0, OptionsHandler.get()); + PackHandler.reset(new PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions)); PP.AddPragmaHandler(0, PackHandler.get()); @@ -134,7 +139,7 @@ SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok, /// returned. bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, const char *Msg, tok::TokenKind SkipToTok) { - if (Tok.is(ExpectedTok)) { + if (Tok.is(ExpectedTok) || Tok.is(tok::code_completion)) { ConsumeAnyToken(); return false; } @@ -189,7 +194,11 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, case tok::eof: // Ran out of tokens. return false; - + + case tok::code_completion: + ConsumeToken(); + return false; + case tok::l_paren: // Recursively skip properly-nested parens. ConsumeParen(); @@ -294,6 +303,8 @@ Parser::~Parser() { delete ScopeCache[i]; // Remove the pragma handlers we installed. + PP.RemovePragmaHandler(0, OptionsHandler.get()); + OptionsHandler.reset(); PP.RemovePragmaHandler(0, PackHandler.get()); PackHandler.reset(); PP.RemovePragmaHandler(0, UnusedHandler.get()); @@ -447,7 +458,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) Actions.CodeCompleteOrdinaryName(CurScope, ObjCImpDecl? Action::CCC_ObjCImplementation : Action::CCC_Namespace); - ConsumeToken(); + ConsumeCodeCompletionToken(); return ParseExternalDeclaration(Attr); case tok::kw_using: case tok::kw_namespace: @@ -538,7 +549,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { ConsumeToken(); - DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -980,10 +991,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + bool MemberOfUnknownSpecialization; if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, TemplateName, /*ObjectType=*/0, EnteringContext, - Template)) { + Template, MemberOfUnknownSpecialization)) { // Consume the identifier. ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) { @@ -1071,6 +1083,22 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { return false; } +void Parser::CodeCompletionRecovery() { + for (Scope *S = CurScope; S; S = S->getParent()) { + if (S->getFlags() & Scope::FnScope) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_RecoveryInFunction); + return; + } + + if (S->getFlags() & Scope::ClassScope) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Class); + return; + } + } + + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Namespace); +} + // Anchor the Parser::FieldCallback vtable to this translation unit. // We use a spurious method instead of the destructor because // destroying FieldCallbacks can actually be slightly diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 6ded0a34601e..448d16116a39 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -54,8 +54,13 @@ static void CheckUnreachable(Sema &S, AnalysisContext &AC) { // Check for missing return value. //===----------------------------------------------------------------------===// -enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, - AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; +enum ControlFlowKind { + UnknownFallThrough, + NeverFallThrough, + MaybeFallThrough, + AlwaysFallThrough, + NeverFallThroughOrReturn +}; /// CheckFallThrough - Check that we don't fall off the end of a /// Statement that should return a value. @@ -68,9 +73,7 @@ enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, /// will return. static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { CFG *cfg = AC.getCFG(); - if (cfg == 0) - // FIXME: This should be NeverFallThrough - return NeverFallThroughOrReturn; + if (cfg == 0) return UnknownFallThrough; // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. @@ -164,6 +167,19 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { } } } + // FIXME: Remove this hack once temporaries and their destructors are + // modeled correctly by the CFG. + if (CXXExprWithTemporaries *E = dyn_cast<CXXExprWithTemporaries>(S)) { + for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) { + const FunctionDecl *FD = E->getTemporary(I)->getDestructor(); + if (FD->hasAttr<NoReturnAttr>() || + FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) { + NoReturnEdge = true; + HasFakeEdge = true; + break; + } + } + } // FIXME: Add noreturn message sends. if (NoReturnEdge == false) HasPlainEdge = true; @@ -290,6 +306,9 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // FIXME: Function try block if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { switch (CheckFallThrough(AC)) { + case UnknownFallThrough: + break; + case MaybeFallThrough: if (HasNoReturn) S.Diag(Compound->getRBracLoc(), diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index ac0dfd6c3af5..b54e8ebfb969 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -34,4 +34,4 @@ add_clang_library(clangSema TargetAttributesSema.cpp ) -add_dependencies(clangSema ClangDiagnosticSema) +add_dependencies(clangSema ClangDiagnosticSema ClangStmtNodes) diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 0ef9a15faaf9..6cefc61f6640 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -210,9 +210,10 @@ CodeCompletionString::Chunk::Destroy() { } } -CodeCompletionString::~CodeCompletionString() { +void CodeCompletionString::clear() { std::for_each(Chunks.begin(), Chunks.end(), std::mem_fun_ref(&Chunk::Destroy)); + Chunks.clear(); } std::string CodeCompletionString::getAsString() const { @@ -310,15 +311,13 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { } } -CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, - const char *StrEnd) { +bool CodeCompletionString::Deserialize(const char *&Str, const char *StrEnd) { if (Str == StrEnd || *Str == 0) - return 0; + return false; - CodeCompletionString *Result = new CodeCompletionString; unsigned NumBlocks; if (ReadUnsigned(Str, StrEnd, NumBlocks)) - return Result; + return false; for (unsigned I = 0; I != NumBlocks; ++I) { if (Str + 1 >= StrEnd) @@ -327,7 +326,7 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, // Parse the next kind. unsigned KindValue; if (ReadUnsigned(Str, StrEnd, KindValue)) - return Result; + return false; switch (ChunkKind Kind = (ChunkKind)KindValue) { case CK_TypedText: @@ -338,16 +337,17 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, case CK_CurrentParameter: { unsigned StrLen; if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd)) - return Result; + return false; - Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen))); + AddChunk(Chunk(Kind, StringRef(Str, StrLen))); Str += StrLen; break; } case CK_Optional: { - std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str, StrEnd)); - Result->AddOptionalChunk(Optional); + std::auto_ptr<CodeCompletionString> Optional(new CodeCompletionString()); + if (Optional->Deserialize(Str, StrEnd)) + AddOptionalChunk(Optional); break; } @@ -365,12 +365,12 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, case CK_Equal: case CK_HorizontalSpace: case CK_VerticalSpace: - Result->AddChunk(Chunk(Kind)); + AddChunk(Chunk(Kind)); break; } }; - return Result; + return true; } void CodeCompleteConsumer::Result::Destroy() { @@ -380,6 +380,25 @@ void CodeCompleteConsumer::Result::Destroy() { } } +unsigned CodeCompleteConsumer::Result::getPriorityFromDecl(NamedDecl *ND) { + if (!ND) + return CCP_Unlikely; + + // Context-based decisions. + DeclContext *DC = ND->getDeclContext()->getLookupContext(); + if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) + return CCP_LocalDeclaration; + if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) + return CCP_MemberDeclaration; + + // Content-based decisions. + if (isa<EnumConstantDecl>(ND)) + return CCP_Constant; + if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) + return CCP_Type; + return CCP_Declaration; +} + //===----------------------------------------------------------------------===// // Code completion overload candidate implementation //===----------------------------------------------------------------------===// @@ -459,11 +478,6 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, } } } - - // Once we've printed the code-completion results, suppress remaining - // diagnostics. - // FIXME: Move this somewhere else! - SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } void @@ -478,11 +492,6 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, delete CCS; } } - - // Once we've printed the code-completion results, suppress remaining - // diagnostics. - // FIXME: Move this somewhere else! - SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } void @@ -594,16 +603,12 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, } WriteUnsigned(OS, Kind); + WriteUnsigned(OS, Results[I].Priority); CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef); assert(CCS && "No code-completion string?"); CCS->Serialize(OS); delete CCS; } - - // Once we've printed the code-completion results, suppress remaining - // diagnostics. - // FIXME: Move this somewhere else! - SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } void @@ -613,15 +618,11 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { WriteUnsigned(OS, CXCursor_NotImplemented); + WriteUnsigned(OS, /*Priority=*/0); CodeCompletionString *CCS = Candidates[I].CreateSignatureString(CurrentArg, SemaRef); assert(CCS && "No code-completion string?"); CCS->Serialize(OS); delete CCS; } - - // Once we've printed the code-completion results, suppress remaining - // diagnostics. - // FIXME: Move this somewhere else! - SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 069429490385..543c1b61edeb 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/BitVector.h" #include "Sema.h" #include "clang/AST/Expr.h" #include "clang/AST/StmtObjC.h" @@ -39,33 +40,47 @@ class JumpScopeChecker { /// the parent scope is the function body. unsigned ParentScope; - /// Diag - The diagnostic to emit if there is a jump into this scope. - unsigned Diag; + /// InDiag - The diagnostic to emit if there is a jump into this scope. + unsigned InDiag; + + /// OutDiag - The diagnostic to emit if there is an indirect jump out + /// of this scope. Direct jumps always clean up their current scope + /// in an orderly way. + unsigned OutDiag; /// Loc - Location to emit the diagnostic. SourceLocation Loc; - GotoScope(unsigned parentScope, unsigned diag, SourceLocation L) - : ParentScope(parentScope), Diag(diag), Loc(L) {} + GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag, + SourceLocation L) + : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {} }; llvm::SmallVector<GotoScope, 48> Scopes; llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; llvm::SmallVector<Stmt*, 16> Jumps; + + llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps; + llvm::SmallVector<LabelStmt*, 4> IndirectJumpTargets; public: JumpScopeChecker(Stmt *Body, Sema &S); private: void BuildScopeInformation(Stmt *S, unsigned ParentScope); void VerifyJumps(); + void VerifyIndirectJumps(); + void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, + LabelStmt *Target, unsigned TargetScope); void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, unsigned JumpDiag); + + unsigned GetDeepestCommonScope(unsigned A, unsigned B); }; } // end anonymous namespace JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { // Add a scope entry for function scope. - Scopes.push_back(GotoScope(~0U, ~0U, SourceLocation())); + Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation())); // Build information for the top level compound statement, so that we have a // defined scope record for every "goto" and label. @@ -73,29 +88,64 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { // Check that all jumps we saw are kosher. VerifyJumps(); + VerifyIndirectJumps(); +} + +/// GetDeepestCommonScope - Finds the innermost scope enclosing the +/// two scopes. +unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) { + while (A != B) { + // Inner scopes are created after outer scopes and therefore have + // higher indices. + if (A < B) { + assert(Scopes[B].ParentScope < B); + B = Scopes[B].ParentScope; + } else { + assert(Scopes[A].ParentScope < A); + A = Scopes[A].ParentScope; + } + } + return A; } /// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a /// diagnostic that should be emitted if control goes over it. If not, return 0. -static unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { +static std::pair<unsigned,unsigned> + GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + unsigned InDiag = 0, OutDiag = 0; if (VD->getType()->isVariablyModifiedType()) - return diag::note_protected_by_vla; - if (VD->hasAttr<CleanupAttr>()) - return diag::note_protected_by_cleanup; - if (VD->hasAttr<BlocksAttr>()) - return diag::note_protected_by___block; - // FIXME: In C++0x, we have to check more conditions than "did we - // just give it an initializer?". See 6.7p3. - if (isCPlusPlus && VD->hasLocalStorage() && VD->hasInit()) - return diag::note_protected_by_variable_init; + InDiag = diag::note_protected_by_vla; + + if (VD->hasAttr<BlocksAttr>()) { + InDiag = diag::note_protected_by___block; + OutDiag = diag::note_exits___block; + } else if (VD->hasAttr<CleanupAttr>()) { + InDiag = diag::note_protected_by_cleanup; + OutDiag = diag::note_exits_cleanup; + } else if (isCPlusPlus) { + // FIXME: In C++0x, we have to check more conditions than "did we + // just give it an initializer?". See 6.7p3. + if (VD->hasLocalStorage() && VD->hasInit()) + InDiag = diag::note_protected_by_variable_init; + + CanQualType T = VD->getType()->getCanonicalTypeUnqualified(); + while (CanQual<ArrayType> AT = T->getAs<ArrayType>()) + T = AT->getElementType(); + if (CanQual<RecordType> RT = T->getAs<RecordType>()) + if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor()) + OutDiag = diag::note_exits_dtor; + } - } else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + return std::make_pair(InDiag, OutDiag); + } + + if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) - return diag::note_protected_by_vla_typedef; + return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0); } - return 0; + return std::make_pair(0U, 0U); } @@ -106,14 +156,32 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // If we found a label, remember that it is in ParentScope scope. - if (isa<LabelStmt>(S) || isa<DefaultStmt>(S) || isa<CaseStmt>(S)) { + switch (S->getStmtClass()) { + case Stmt::LabelStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::CaseStmtClass: + LabelAndGotoScopes[S] = ParentScope; + break; + + case Stmt::AddrLabelExprClass: + IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel()); + break; + + case Stmt::IndirectGotoStmtClass: LabelAndGotoScopes[S] = ParentScope; - } else if (isa<GotoStmt>(S) || isa<SwitchStmt>(S) || - isa<IndirectGotoStmt>(S) || isa<AddrLabelExpr>(S)) { + IndirectJumps.push_back(cast<IndirectGotoStmt>(S)); + break; + + case Stmt::GotoStmtClass: + case Stmt::SwitchStmtClass: // Remember both what scope a goto is in as well as the fact that we have // it. This makes the second scan not have to walk the AST again. LabelAndGotoScopes[S] = ParentScope; Jumps.push_back(S); + break; + + default: + break; } for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; @@ -131,8 +199,11 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { // If this decl causes a new scope, push and switch to it. - if (unsigned Diag = GetDiagForGotoScopeDecl(*I, isCPlusPlus)) { - Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation())); + std::pair<unsigned,unsigned> Diags + = GetDiagForGotoScopeDecl(*I, isCPlusPlus); + if (Diags.first || Diags.second) { + Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second, + (*I)->getLocation())); ParentScope = Scopes.size()-1; } @@ -149,7 +220,9 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // walking all sub-stmts in that scope. if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { // Recursively walk the AST for the @try part. - Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_try, + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_try, + diag::note_exits_objc_try, AT->getAtTryLoc())); if (Stmt *TryPart = AT->getTryBody()) BuildScopeInformation(TryPart, Scopes.size()-1); @@ -159,6 +232,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { ObjCAtCatchStmt *AC = AT->getCatchStmt(I); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_catch, + diag::note_exits_objc_catch, AC->getAtCatchLoc())); // @catches are nested and it isn't BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1); @@ -168,6 +242,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_finally, + diag::note_exits_objc_finally, AF->getAtFinallyLoc())); BuildScopeInformation(AF, Scopes.size()-1); } @@ -186,6 +261,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // scope. Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_synchronized, + diag::note_exits_objc_synchronized, AS->getAtSynchronizedLoc())); BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1); continue; @@ -194,7 +270,9 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // Disallow jumps into any part of a C++ try statement. This is pretty // much the same as for Obj-C. if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) { - Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_try, + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_cxx_try, + diag::note_exits_cxx_try, TS->getSourceRange().getBegin())); if (Stmt *TryBlock = TS->getTryBlock()) BuildScopeInformation(TryBlock, Scopes.size()-1); @@ -204,6 +282,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { CXXCatchStmt *CS = TS->getHandler(I); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_catch, + diag::note_exits_cxx_catch, CS->getSourceRange().getBegin())); BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1); } @@ -229,54 +308,178 @@ void JumpScopeChecker::VerifyJumps() { continue; } - if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) { - for (SwitchCase *SC = SS->getSwitchCaseList(); SC; - SC = SC->getNextSwitchCase()) { - assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); - CheckJump(SS, SC, SC->getLocStart(), - diag::err_switch_into_protected_scope); - } - continue; + SwitchStmt *SS = cast<SwitchStmt>(Jump); + for (SwitchCase *SC = SS->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); + CheckJump(SS, SC, SC->getLocStart(), + diag::err_switch_into_protected_scope); } + } +} - unsigned DiagnosticScope; - - // We don't know where an indirect goto goes, require that it be at the - // top level of scoping. - if (IndirectGotoStmt *IG = dyn_cast<IndirectGotoStmt>(Jump)) { - assert(LabelAndGotoScopes.count(Jump) && - "Jump didn't get added to scopes?"); - unsigned GotoScope = LabelAndGotoScopes[IG]; - if (GotoScope == 0) continue; // indirect jump is ok. - S.Diag(IG->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); - DiagnosticScope = GotoScope; - } else { - // We model &&Label as a jump for purposes of scope tracking. We actually - // don't care *where* the address of label is, but we require the *label - // itself* to be in scope 0. If it is nested inside of a VLA scope, then - // it is possible for an indirect goto to illegally enter the VLA scope by - // indirectly jumping to the label. - assert(isa<AddrLabelExpr>(Jump) && "Unknown jump type"); - LabelStmt *TheLabel = cast<AddrLabelExpr>(Jump)->getLabel(); - - assert(LabelAndGotoScopes.count(TheLabel) && - "Referenced label didn't get added to scopes?"); - unsigned LabelScope = LabelAndGotoScopes[TheLabel]; - if (LabelScope == 0) continue; // Addr of label is ok. - - S.Diag(Jump->getLocStart(), diag::err_addr_of_label_in_protected_scope); - DiagnosticScope = LabelScope; +/// VerifyIndirectJumps - Verify whether any possible indirect jump +/// might cross a protection boundary. Unlike direct jumps, indirect +/// jumps count cleanups as protection boundaries: since there's no +/// way to know where the jump is going, we can't implicitly run the +/// right cleanups the way we can with direct jumps. +/// +/// Thus, an indirect jump is "trivial" if it bypasses no +/// initializations and no teardowns. More formally, an indirect jump +/// from A to B is trivial if the path out from A to DCA(A,B) is +/// trivial and the path in from DCA(A,B) to B is trivial, where +/// DCA(A,B) is the deepest common ancestor of A and B. +/// Jump-triviality is transitive but asymmetric. +/// +/// A path in is trivial if none of the entered scopes have an InDiag. +/// A path out is trivial is none of the exited scopes have an OutDiag. +/// +/// Under these definitions, this function checks that the indirect +/// jump between A and B is trivial for every indirect goto statement A +/// and every label B whose address was taken in the function. +void JumpScopeChecker::VerifyIndirectJumps() { + if (IndirectJumps.empty()) return; + + // If there aren't any address-of-label expressions in this function, + // complain about the first indirect goto. + if (IndirectJumpTargets.empty()) { + S.Diag(IndirectJumps[0]->getGotoLoc(), + diag::err_indirect_goto_without_addrlabel); + return; + } + + // Collect a single representative of every scope containing an + // indirect goto. For most code bases, this substantially cuts + // down on the number of jump sites we'll have to consider later. + typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope; + llvm::SmallVector<JumpScope, 32> JumpScopes; + { + llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap; + for (llvm::SmallVectorImpl<IndirectGotoStmt*>::iterator + I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { + IndirectGotoStmt *IG = *I; + assert(LabelAndGotoScopes.count(IG) && + "indirect jump didn't get added to scopes?"); + unsigned IGScope = LabelAndGotoScopes[IG]; + IndirectGotoStmt *&Entry = JumpScopesMap[IGScope]; + if (!Entry) Entry = IG; + } + JumpScopes.reserve(JumpScopesMap.size()); + for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator + I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I) + JumpScopes.push_back(*I); + } + + // Collect a single representative of every scope containing a + // label whose address was taken somewhere in the function. + // For most code bases, there will be only one such scope. + llvm::DenseMap<unsigned, LabelStmt*> TargetScopes; + for (llvm::SmallVectorImpl<LabelStmt*>::iterator + I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); + I != E; ++I) { + LabelStmt *TheLabel = *I; + assert(LabelAndGotoScopes.count(TheLabel) && + "Referenced label didn't get added to scopes?"); + unsigned LabelScope = LabelAndGotoScopes[TheLabel]; + LabelStmt *&Target = TargetScopes[LabelScope]; + if (!Target) Target = TheLabel; + } + + // For each target scope, make sure it's trivially reachable from + // every scope containing a jump site. + // + // A path between scopes always consists of exitting zero or more + // scopes, then entering zero or more scopes. We build a set of + // of scopes S from which the target scope can be trivially + // entered, then verify that every jump scope can be trivially + // exitted to reach a scope in S. + llvm::BitVector Reachable(Scopes.size(), false); + for (llvm::DenseMap<unsigned,LabelStmt*>::iterator + TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) { + unsigned TargetScope = TI->first; + LabelStmt *TargetLabel = TI->second; + + Reachable.reset(); + + // Mark all the enclosing scopes from which you can safely jump + // into the target scope. 'Min' will end up being the index of + // the shallowest such scope. + unsigned Min = TargetScope; + while (true) { + Reachable.set(Min); + + // Don't go beyond the outermost scope. + if (Min == 0) break; + + // Stop if we can't trivially enter the current scope. + if (Scopes[Min].InDiag) break; + + Min = Scopes[Min].ParentScope; } - // Report all the things that would be skipped over by this &&label or - // indirect goto. - while (DiagnosticScope != 0) { - S.Diag(Scopes[DiagnosticScope].Loc, Scopes[DiagnosticScope].Diag); - DiagnosticScope = Scopes[DiagnosticScope].ParentScope; + // Walk through all the jump sites, checking that they can trivially + // reach this label scope. + for (llvm::SmallVectorImpl<JumpScope>::iterator + I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { + unsigned Scope = I->first; + + // Walk out the "scope chain" for this scope, looking for a scope + // we've marked reachable. For well-formed code this amortizes + // to O(JumpScopes.size() / Scopes.size()): we only iterate + // when we see something unmarked, and in well-formed code we + // mark everything we iterate past. + bool IsReachable = false; + while (true) { + if (Reachable.test(Scope)) { + // If we find something reachable, mark all the scopes we just + // walked through as reachable. + for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope) + Reachable.set(S); + IsReachable = true; + break; + } + + // Don't walk out if we've reached the top-level scope or we've + // gotten shallower than the shallowest reachable scope. + if (Scope == 0 || Scope < Min) break; + + // Don't walk out through an out-diagnostic. + if (Scopes[Scope].OutDiag) break; + + Scope = Scopes[Scope].ParentScope; + } + + // Only diagnose if we didn't find something. + if (IsReachable) continue; + + DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope); } } } +/// Diagnose an indirect jump which is known to cross scopes. +void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, + unsigned JumpScope, + LabelStmt *Target, + unsigned TargetScope) { + assert(JumpScope != TargetScope); + + S.Diag(Jump->getGotoLoc(), diag::warn_indirect_goto_in_protected_scope); + S.Diag(Target->getIdentLoc(), diag::note_indirect_goto_target); + + unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope); + + // Walk out the scope chain until we reach the common ancestor. + for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope) + if (Scopes[I].OutDiag) + S.Diag(Scopes[I].Loc, Scopes[I].OutDiag); + + // Now walk into the scopes containing the label whose address was taken. + for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope) + if (Scopes[I].InDiag) + S.Diag(Scopes[I].Loc, Scopes[I].InDiag); +} + /// CheckJump - Validate that the specified jump statement is valid: that it is /// jumping within or out of its current scope, not into a deeper one. void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, @@ -290,42 +493,25 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, // Common case: exactly the same scope, which is fine. if (FromScope == ToScope) return; - // The only valid mismatch jump case happens when the jump is more deeply - // nested inside the jump target. Do a quick scan to see if the jump is valid - // because valid code is more common than invalid code. - unsigned TestScope = Scopes[FromScope].ParentScope; - while (TestScope != ~0U) { - // If we found the jump target, then we're jumping out of our current scope, - // which is perfectly fine. - if (TestScope == ToScope) return; - - // Otherwise, scan up the hierarchy. - TestScope = Scopes[TestScope].ParentScope; - } + unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope); - // If we get here, then we know we have invalid code. Diagnose the bad jump, - // and then emit a note at each VLA being jumped out of. - S.Diag(DiagLoc, JumpDiag); + // It's okay to jump out from a nested scope. + if (CommonScope == ToScope) return; - // Eliminate the common prefix of the jump and the target. Start by - // linearizing both scopes, reversing them as we go. - std::vector<unsigned> FromScopes, ToScopes; - for (TestScope = FromScope; TestScope != ~0U; - TestScope = Scopes[TestScope].ParentScope) - FromScopes.push_back(TestScope); - for (TestScope = ToScope; TestScope != ~0U; - TestScope = Scopes[TestScope].ParentScope) - ToScopes.push_back(TestScope); - - // Remove any common entries (such as the top-level function scope). - while (!FromScopes.empty() && FromScopes.back() == ToScopes.back()) { - FromScopes.pop_back(); - ToScopes.pop_back(); - } + // Pull out (and reverse) any scopes we might need to diagnose skipping. + llvm::SmallVector<unsigned, 10> ToScopes; + for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) + if (Scopes[I].InDiag) + ToScopes.push_back(I); + + // If the only scopes present are cleanup scopes, we're okay. + if (ToScopes.empty()) return; + + S.Diag(DiagLoc, JumpDiag); // Emit diagnostics for whatever is left in ToScopes. for (unsigned i = 0, e = ToScopes.size(); i != e; ++i) - S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].Diag); + S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].InDiag); } void Sema::DiagnoseInvalidJumps(Stmt *Body) { diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 755af84ca960..523b19639228 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -33,22 +33,12 @@ void FunctionScopeInfo::Clear(unsigned NumErrors) { NeedsScopeChecking = false; LabelMap.clear(); SwitchStack.clear(); + Returns.clear(); NumErrorsAtStartOfFunction = NumErrors; } BlockScopeInfo::~BlockScopeInfo() { } -static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) { - if (C.getLangOptions().CPlusPlus) - return CXXRecordDecl::Create(C, TagDecl::TK_struct, - C.getTranslationUnitDecl(), - SourceLocation(), &C.Idents.get(Name)); - - return RecordDecl::Create(C, TagDecl::TK_struct, - C.getTranslationUnitDecl(), - SourceLocation(), &C.Idents.get(Name)); -} - void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { TUScope = S; PushDeclContext(S, Context.getTranslationUnitDecl()); @@ -97,8 +87,9 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { } // Create the built-in typedef for 'id'. if (Context.getObjCIdType().isNull()) { - QualType IdT = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy); - TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(IdT); + QualType T = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, 0, 0); + T = Context.getObjCObjectPointerType(T); + TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(T); TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("id"), IdInfo); @@ -108,9 +99,9 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { } // Create the built-in typedef for 'Class'. if (Context.getObjCClassType().isNull()) { - QualType ClassType - = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy); - TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(ClassType); + QualType T = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, 0, 0); + T = Context.getObjCObjectPointerType(T); + TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(T); TypedefDecl *ClassTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("Class"), ClassInfo); @@ -175,7 +166,17 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, } } - CheckImplicitConversion(Expr, Ty); + // If this is a derived-to-base cast to a through a virtual base, we + // need a vtable. + if (Kind == CastExpr::CK_DerivedToBase && + BasePathInvolvesVirtualBase(BasePath)) { + QualType T = Expr->getType(); + if (const PointerType *Pointer = T->getAs<PointerType>()) + T = Pointer->getPointeeType(); + if (const RecordType *RecordTy = T->getAs<RecordType>()) + MarkVTableUsed(Expr->getLocStart(), + cast<CXXRecordDecl>(RecordTy->getDecl())); + } if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { if (ImpCast->getCastKind() == Kind && BasePath.empty()) { @@ -212,10 +213,10 @@ void Sema::ActOnEndOfTranslationUnit() { // template instantiations earlier. PerformPendingImplicitInstantiations(); - /// If ProcessPendingClassesWithUnmarkedVirtualMembers ends up marking - /// any virtual member functions it might lead to more pending template + /// If DefinedUsedVTables ends up marking any virtual member + /// functions it might lead to more pending template /// instantiations, which is why we need to loop here. - if (!ProcessPendingClassesWithUnmarkedVirtualMembers()) + if (!DefineUsedVTables()) break; } @@ -304,7 +305,7 @@ void Sema::ActOnEndOfTranslationUnit() { DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; - while (isa<BlockDecl>(DC)) + while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) DC = DC->getParent(); return DC; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index f146c8578721..dfc45ace0e03 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -134,6 +134,11 @@ struct FunctionScopeInfo { /// block. llvm::SmallVector<SwitchStmt*, 8> SwitchStack; + /// \brief The list of return statements that occur within the function or + /// block, if there is any chance of applying the named return value + /// optimization. + llvm::SmallVector<ReturnStmt *, 4> Returns; + FunctionScopeInfo(unsigned NumErrors) : IsBlockInfo(false), NeedsScopeChecking(false), NumErrorsAtStartOfFunction(NumErrors) { } @@ -768,7 +773,8 @@ public: bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID); - QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T); + QualType getElaboratedType(ElaboratedTypeKeyword Keyword, + const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E); QualType BuildDecltypeType(Expr *E); @@ -901,11 +907,11 @@ public: /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS); + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS); - bool InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, - RecordDecl *AnonRecord); virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, RecordDecl *Record); bool isAcceptableTagRedeclaration(const TagDecl *Previous, @@ -1161,6 +1167,9 @@ public: ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); bool PerformContextuallyConvertToBool(Expr *&From); + ImplicitConversionSequence TryContextuallyConvertToObjCId(Expr *From); + bool PerformContextuallyConvertToObjCId(Expr *&From); + bool PerformObjectMemberConversion(Expr *&From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, @@ -1528,16 +1537,21 @@ public: /// ImplMethodsVsClassMethods - This is main routine to warn if any method /// remains unimplemented in the class or category @implementation. - void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, + void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); /// DiagnoseUnimplementedProperties - This routine warns on those properties /// which must be implemented by this implementation. - void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, + void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet<Selector>& InsMap); + /// DefaultSynthesizeProperties - This routine default synthesizes all + /// properties which must be synthesized in class's @implementation. + void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl *IDecl); + /// CollectImmediateProperties - This routine collects all properties in /// the class and its conforming protocols; but not those it its super class. void CollectImmediateProperties(ObjCContainerDecl *CDecl, @@ -1583,7 +1597,8 @@ public: const bool isAssign, const bool isReadWrite, const unsigned Attributes, QualType T, - tok::ObjCKeywordKind MethodImplKind); + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = 0); /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared @@ -1661,10 +1676,9 @@ public: FullExprArg CondVal, DeclPtrTy CondVar, StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal); - virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + ExprArg Cond, DeclPtrTy CondVar); - virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, - StmtArg Body); virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body); virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, @@ -1762,7 +1776,8 @@ public: /// DiagnoseUnusedExprResult - If the statement passed in is an expression /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); - + void DiagnoseUnusedDecl(const NamedDecl *ND); + ParsingDeclStackState PushParsingDeclaration(); void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D); void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc); @@ -1785,6 +1800,7 @@ public: virtual void PopExpressionEvaluationContext(); void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); + void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD); // Primary Expressions. @@ -1796,7 +1812,8 @@ public: bool HasTrailingLParen, bool IsAddressOfOperand); - bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R); + bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, + CorrectTypoContext CTC = CTC_Unknown); OwningExprResult LookupInObjCMethod(LookupResult &R, Scope *S, @@ -2321,7 +2338,9 @@ public: virtual DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); - OwningExprResult CheckConditionVariable(VarDecl *ConditionVar); + OwningExprResult CheckConditionVariable(VarDecl *ConditionVar, + SourceLocation StmtLoc, + bool ConvertToBoolean); /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support /// pseudo-functions. @@ -2553,27 +2572,38 @@ public: void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, CXXRecordDecl *Record); - /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual - /// members need to be marked as referenced at the end of the translation - /// unit. It will contain polymorphic classes that do not have a key - /// function or have a key function that has been defined. - llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 4> - ClassesWithUnmarkedVirtualMembers; + /// \brief The list of classes whose vtables have been used within + /// this translation unit, and the source locations at which the + /// first use occurred. + llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 16> + VTableUses; - /// MaybeMarkVirtualMembersReferenced - If the passed in method is the - /// key function of the record decl, will mark virtual member functions as - /// referenced. - void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD); + /// \brief The set of classes whose vtables have been used within + /// this translation unit, and a bit that will be true if the vtable is + /// required to be emitted (otherwise, it should be emitted only if needed + /// by code generation). + llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed; + + /// \brief A list of all of the dynamic classes in this translation + /// unit. + llvm::SmallVector<CXXRecordDecl *, 16> DynamicClasses; + + /// \brief Note that the vtable for the given class was used at the + /// given location. + void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, + bool DefinitionRequired = false); /// MarkVirtualMembersReferenced - Will mark all virtual members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD); - /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes - /// that might need to have their virtual members marked as referenced. - /// Returns false if no work was done. - bool ProcessPendingClassesWithUnmarkedVirtualMembers(); + /// \brief Define all of the vtables that have been used in this + /// translation unit and reference any virtual members used by those + /// vtables. + /// + /// \returns true if any work was done, false otherwise. + bool DefineUsedVTables(); void AddImplicitlyDeclaredMembersToClass(Scope *S, CXXRecordDecl *ClassDecl); @@ -2657,6 +2687,8 @@ public: void BuildBasePathArray(const CXXBasePaths &Paths, CXXBaseSpecifierArray &BasePath); + bool BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, CXXBaseSpecifierArray *BasePath = 0, @@ -2768,14 +2800,16 @@ public: // C++ Templates [C++ 14] // void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, - QualType ObjectType, bool EnteringContext); + QualType ObjectType, bool EnteringContext, + bool &MemberOfUnknownSpecialization); virtual TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, - TemplateTy &Template); + TemplateTy &Template, + bool &MemberOfUnknownSpecialization); virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, @@ -3085,7 +3119,9 @@ public: QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo &II, - SourceRange Range); + SourceLocation KeywordLoc, + SourceRange NNSRange, + SourceLocation IILoc); TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, SourceLocation Loc, @@ -3568,6 +3604,24 @@ public: } }; + /// \brief RAII class that determines when any errors have occurred + /// between the time the instance was created and the time it was + /// queried. + class ErrorTrap { + Sema &SemaRef; + unsigned PrevErrors; + + public: + explicit ErrorTrap(Sema &SemaRef) + : SemaRef(SemaRef), PrevErrors(SemaRef.getDiagnostics().getNumErrors()) {} + + /// \brief Determine whether any errors have occurred since this + /// object instance was created. + bool hasErrorOccurred() const { + return SemaRef.getDiagnostics().getNumErrors() > PrevErrors; + } + }; + /// \brief A stack-allocated class that identifies which local /// variable declaration instantiations are present in this scope. /// @@ -3858,7 +3912,7 @@ public: void MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl); - virtual void ActOnAtEnd(SourceRange AtEnd, + virtual void ActOnAtEnd(Scope *S, SourceRange AtEnd, DeclPtrTy classDecl, DeclPtrTy *allMethods = 0, unsigned allNum = 0, DeclPtrTy *allProperties = 0, unsigned pNum = 0, @@ -3871,7 +3925,8 @@ public: bool *OverridingProperty, tok::ObjCKeywordKind MethodImplKind); - virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc, + virtual DeclPtrTy ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind,DeclPtrTy ClassImplDecl, IdentifierInfo *PropertyId, @@ -3960,6 +4015,11 @@ public: MultiExprArg Args); + /// ActOnPragmaOptionsAlign - Called on well formed #pragma options align. + virtual void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, + SourceLocation PragmaLoc, + SourceLocation KindLoc); + /// ActOnPragmaPack - Called on well formed #pragma pack(...). virtual void ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, @@ -3990,9 +4050,9 @@ public: SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); - /// getPragmaPackAlignment() - Return the current alignment as specified by - /// the current #pragma pack directive, or 0 if none is currently active. - unsigned getPragmaPackAlignment() const; + /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to + /// a the record decl, to handle '#pragma pack' and '#pragma options align'. + void AddAlignmentAttributesForRecord(RecordDecl *RD); /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); @@ -4044,7 +4104,8 @@ public: // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will warn if the resulting type is not a POD type. - bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT); + bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, + FunctionDecl *FDecl); // UsualArithmeticConversions - performs the UsualUnaryConversions on it's // operands and then handles various conversions that are common to binary @@ -4215,9 +4276,9 @@ public: SourceLocation questionLoc); /// type checking for vector binary operators. - inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); - inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, - SourceLocation l, bool isRel); + QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); + QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, + SourceLocation l, bool isRel); /// type checking unary operators (subroutines of ActOnUnaryOp). /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 @@ -4311,6 +4372,9 @@ public: /// \return true iff there were any errors bool CheckBooleanCondition(Expr *&CondExpr, SourceLocation Loc); + virtual OwningExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc, + ExprArg SubExpr); + /// DiagnoseAssignmentAsCondition - Given that an expression is /// being used as a boolean condition, warn if it's an assignment. void DiagnoseAssignmentAsCondition(Expr *E); @@ -4455,9 +4519,7 @@ private: void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc); void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); - void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, - const BinaryOperator::Opcode* BinOpc = 0); - void CheckImplicitConversion(Expr *E, QualType Target); + void CheckImplicitConversions(Expr *E); }; //===--------------------------------------------------------------------===// diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 095f537f7102..82978c956053 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -15,17 +15,28 @@ #include "Sema.h" #include "Lookup.h" #include "clang/AST/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" using namespace clang; //===----------------------------------------------------------------------===// -// Pragma Packed +// Pragma 'pack' and 'options align' //===----------------------------------------------------------------------===// namespace { + struct PackStackEntry { + // We just use a sentinel to represent when the stack is set to mac68k + // alignment. + static const unsigned kMac68kAlignmentSentinel = ~0U; + + unsigned Alignment; + IdentifierInfo *Name; + }; + /// PragmaPackStack - Simple class to wrap the stack used by #pragma /// pack. class PragmaPackStack { - typedef std::vector< std::pair<unsigned, IdentifierInfo*> > stack_ty; + typedef std::vector<PackStackEntry> stack_ty; /// Alignment - The current user specified alignment. unsigned Alignment; @@ -43,7 +54,8 @@ namespace { /// push - Push the current alignment onto the stack, optionally /// using the given \arg Name for the record, if non-zero. void push(IdentifierInfo *Name) { - Stack.push_back(std::make_pair(Alignment, Name)); + PackStackEntry PSE = { Alignment, Name }; + Stack.push_back(PSE); } /// pop - Pop a record from the stack and restore the current @@ -60,7 +72,7 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) { // If name is empty just pop top. if (!Name) { - Alignment = Stack.back().first; + Alignment = Stack.back().Alignment; Stack.pop_back(); return true; } @@ -68,9 +80,9 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) { // Otherwise, find the named record. for (unsigned i = Stack.size(); i != 0; ) { --i; - if (Stack[i].second == Name) { + if (Stack[i].Name == Name) { // Found it, pop up to and including this record. - Alignment = Stack[i].first; + Alignment = Stack[i].Alignment; Stack.erase(Stack.begin() + i, Stack.end()); return true; } @@ -86,12 +98,65 @@ void Sema::FreePackedContext() { PackContext = 0; } -/// getPragmaPackAlignment() - Return the current alignment as specified by -/// the current #pragma pack directive, or 0 if none is currently active. -unsigned Sema::getPragmaPackAlignment() const { - if (PackContext) - return static_cast<PragmaPackStack*>(PackContext)->getAlignment(); - return 0; +void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) { + // If there is no pack context, we don't need any attributes. + if (!PackContext) + return; + + PragmaPackStack *Stack = static_cast<PragmaPackStack*>(PackContext); + + // Otherwise, check to see if we need a max field alignment attribute. + if (unsigned Alignment = Stack->getAlignment()) { + if (Alignment == PackStackEntry::kMac68kAlignmentSentinel) + RD->addAttr(::new (Context) AlignMac68kAttr()); + else + RD->addAttr(::new (Context) MaxFieldAlignmentAttr(Alignment * 8)); + } +} + +void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, + SourceLocation PragmaLoc, + SourceLocation KindLoc) { + if (PackContext == 0) + PackContext = new PragmaPackStack(); + + PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext); + + // Reset just pops the top of the stack. + if (Kind == Action::POAK_Reset) { + // Do the pop. + if (!Context->pop(0)) { + // If a name was specified then failure indicates the name + // wasn't found. Otherwise failure indicates the stack was + // empty. + Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed) + << "stack empty"; + } + return; + } + + // We don't support #pragma options align=power. + switch (Kind) { + case POAK_Natural: + Context->push(0); + Context->setAlignment(0); + break; + + case POAK_Mac68k: + // Check if the target supports this. + if (!PP.getTargetInfo().hasAlignMac68kSupport()) { + Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported); + return; + } + Context->push(0); + Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel); + break; + + default: + Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option) + << KindLoc; + break; + } } void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, @@ -106,7 +171,9 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, // pack(0) is like pack(), which just works out since that is what // we use 0 for in PackAttr. - if (!Alignment->isIntegerConstantExpr(Val, Context) || + if (Alignment->isTypeDependent() || + Alignment->isValueDependent() || + !Alignment->isIntegerConstantExpr(Val, Context) || !(Val == 0 || Val.isPowerOf2()) || Val.getZExtValue() > 16) { Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment); @@ -134,7 +201,10 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, // FIXME: This should come from the target. if (AlignmentVal == 0) AlignmentVal = 8; - Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal; + if (AlignmentVal == PackStackEntry::kMac68kAlignmentSentinel) + Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k"; + else + Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal; break; case Action::PPK_Push: // pack(push [, id] [, [n]) diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index ba7e1ff6341b..9b9555255489 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -388,6 +388,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, return; Kind = CastExpr::CK_DerivedToBase; + + // If we are casting to or through a virtual base class, we need a + // vtable. + if (Self.BasePathInvolvesVirtualBase(BasePath)) + Self.MarkVTableUsed(OpRange.getBegin(), + cast<CXXRecordDecl>(SrcRecord->getDecl())); return; } @@ -398,6 +404,8 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); } + Self.MarkVTableUsed(OpRange.getBegin(), + cast<CXXRecordDecl>(SrcRecord->getDecl())); // Done. Everything else is run-time checks. Kind = CastExpr::CK_Dynamic; @@ -578,8 +586,9 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, return TC_Success; } } - else if (CStyle && DestType->isObjCObjectPointerType()) { - // allow c-style cast of objective-c pointers as they are pervasive. + else if (DestType->isObjCObjectPointerType()) { + // allow both c-style cast and static_cast of objective-c pointers as + // they are pervasive. Kind = CastExpr::CK_AnyPointerToObjCPointerCast; return TC_Success; } @@ -590,7 +599,11 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, } } } - + // Allow arbitray objective-c pointer conversion with static casts. + if (SrcType->isObjCObjectPointerType() && + DestType->isObjCObjectPointerType()) + return TC_Success; + // We tried everything. Everything! Nothing works! :-( return TC_NotApplicable; } @@ -846,7 +859,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, } // B is a base of D. But is it an allowed base? If not, it's a hard error. - if (Paths.isAmbiguous(DestClass)) { + if (Paths.isAmbiguous(Self.Context.getCanonicalType(DestClass))) { Paths.clear(); Paths.setRecordingPaths(true); bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths); @@ -970,7 +983,9 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, // C++ 5.2.11p5: For a const_cast involving pointers to data members [...] // the rules for const_cast are the same as those used for pointers. - if (!DestType->isPointerType() && !DestType->isMemberPointerType()) { + if (!DestType->isPointerType() && + !DestType->isMemberPointerType() && + !DestType->isObjCObjectPointerType()) { // Cannot cast to non-pointer, non-reference type. Note that, if DestType // was a reference type, we converted it to a pointer above. // The status of rvalue references isn't entirely clear, but it looks like diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 7029711d446c..4f3f41b715f9 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -75,14 +75,15 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, TheLexer.LexFromRawLexer(TheTok); // Use the StringLiteralParser to compute the length of the string in bytes. - StringLiteralParser SLP(&TheTok, 1, PP); + StringLiteralParser SLP(&TheTok, 1, PP, /*Complain=*/false); unsigned TokNumBytes = SLP.GetStringLength(); // If the byte is in this token, return the location of the byte. if (ByteNo < TokNumBytes || (ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) { unsigned Offset = - StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP); + StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP, + /*Complain=*/false); // Now that we know the offset of the token in the spelling, use the // preprocessor to get the offset in the original source. @@ -607,12 +608,25 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { if (OrigArg->isTypeDependent()) return false; - // This operation requires a floating-point number + // This operation requires a non-_Complex floating-point number. if (!OrigArg->getType()->isRealFloatingType()) return Diag(OrigArg->getLocStart(), diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); + // If this is an implicit conversion from float -> double, remove it. + if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) { + Expr *CastArg = Cast->getSubExpr(); + if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { + assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) && + "promotion from float to double is the only expected cast here"); + Cast->setSubExpr(0); + Cast->Destroy(Context); + TheCall->setArg(NumArgs-1, CastArg); + OrigArg = CastArg; + } + } + return false; } @@ -1718,8 +1732,14 @@ struct IntRange { T = VT->getElementType().getTypePtr(); if (const ComplexType *CT = dyn_cast<ComplexType>(T)) T = CT->getElementType().getTypePtr(); - if (const EnumType *ET = dyn_cast<EnumType>(T)) - T = ET->getDecl()->getIntegerType().getTypePtr(); + + if (const EnumType *ET = dyn_cast<EnumType>(T)) { + EnumDecl *Enum = ET->getDecl(); + unsigned NumPositive = Enum->getNumPositiveBits(); + unsigned NumNegative = Enum->getNumNegativeBits(); + + return IntRange(std::max(NumPositive, NumNegative), NumNegative == 0); + } const BuiltinType *BT = cast<BuiltinType>(T); assert(BT->isInteger()); @@ -1961,6 +1981,10 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { return IntRange::forType(C, E->getType()); } +IntRange GetExprRange(ASTContext &C, Expr *E) { + return GetExprRange(C, E, C.getIntWidth(E->getType())); +} + /// Checks whether the given value, which currently has the given /// source semantics, has the same value when coerced through the /// target semantics. @@ -1999,7 +2023,40 @@ bool IsSameFloatAfterCast(const APValue &value, IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } -} // end anonymous namespace +void AnalyzeImplicitConversions(Sema &S, Expr *E); + +bool IsZero(Sema &S, Expr *E) { + llvm::APSInt Value; + return E->isIntegerConstantExpr(Value, S.Context) && Value == 0; +} + +void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { + BinaryOperator::Opcode op = E->getOpcode(); + if (op == BinaryOperator::LT && IsZero(S, E->getRHS())) { + S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) + << "< 0" << "false" + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + } else if (op == BinaryOperator::GE && IsZero(S, E->getRHS())) { + S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) + << ">= 0" << "true" + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + } else if (op == BinaryOperator::GT && IsZero(S, E->getLHS())) { + S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) + << "0 >" << "false" + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + } else if (op == BinaryOperator::LE && IsZero(S, E->getLHS())) { + S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) + << "0 <=" << "true" + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + } +} + +/// Analyze the operands of the given comparison. Implements the +/// fallback case from AnalyzeComparison. +void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { + AnalyzeImplicitConversions(S, E->getLHS()); + AnalyzeImplicitConversions(S, E->getRHS()); +} /// \brief Implements -Wsign-compare. /// @@ -2007,138 +2064,85 @@ bool IsSameFloatAfterCast(const APValue &value, /// \param rex the right-hand expression /// \param OpLoc the location of the joining operator /// \param BinOpc binary opcode or 0 -void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, - const BinaryOperator::Opcode* BinOpc) { - // Don't warn if we're in an unevaluated context. - if (ExprEvalContexts.back().Context == Unevaluated) - return; - - // If either expression is value-dependent, don't warn. We'll get another - // chance at instantiation time. - if (lex->isValueDependent() || rex->isValueDependent()) - return; - - QualType lt = lex->getType(), rt = rex->getType(); - - // Only warn if both operands are integral. - if (!lt->isIntegerType() || !rt->isIntegerType()) - return; - - // In C, the width of a bitfield determines its type, and the - // declared type only contributes the signedness. This duplicates - // the work that will later be done by UsualUnaryConversions. - // Eventually, this check will be reorganized in a way that avoids - // this duplication. - if (!getLangOptions().CPlusPlus) { - QualType tmp; - tmp = Context.isPromotableBitField(lex); - if (!tmp.isNull()) lt = tmp; - tmp = Context.isPromotableBitField(rex); - if (!tmp.isNull()) rt = tmp; - } - - if (const EnumType *E = lt->getAs<EnumType>()) - lt = E->getDecl()->getPromotionType(); - if (const EnumType *E = rt->getAs<EnumType>()) - rt = E->getDecl()->getPromotionType(); - - // The rule is that the signed operand becomes unsigned, so isolate the - // signed operand. - Expr *signedOperand = lex, *unsignedOperand = rex; - QualType signedType = lt, unsignedType = rt; - if (lt->isSignedIntegerType()) { - if (rt->isSignedIntegerType()) return; +void AnalyzeComparison(Sema &S, BinaryOperator *E) { + // The type the comparison is being performed in. + QualType T = E->getLHS()->getType(); + assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType()) + && "comparison with mismatched types"); + + // We don't do anything special if this isn't an unsigned integral + // comparison: we're only interested in integral comparisons, and + // signed comparisons only happen in cases we don't care to warn about. + if (!T->isUnsignedIntegerType()) + return AnalyzeImpConvsInComparison(S, E); + + Expr *lex = E->getLHS()->IgnoreParenImpCasts(); + Expr *rex = E->getRHS()->IgnoreParenImpCasts(); + + // Check to see if one of the (unmodified) operands is of different + // signedness. + Expr *signedOperand, *unsignedOperand; + if (lex->getType()->isSignedIntegerType()) { + assert(!rex->getType()->isSignedIntegerType() && + "unsigned comparison between two signed integer expressions?"); + signedOperand = lex; + unsignedOperand = rex; + } else if (rex->getType()->isSignedIntegerType()) { + signedOperand = rex; + unsignedOperand = lex; } else { - if (!rt->isSignedIntegerType()) return; - std::swap(signedOperand, unsignedOperand); - std::swap(signedType, unsignedType); + CheckTrivialUnsignedComparison(S, E); + return AnalyzeImpConvsInComparison(S, E); } - unsigned unsignedWidth = Context.getIntWidth(unsignedType); - unsigned signedWidth = Context.getIntWidth(signedType); + // Otherwise, calculate the effective range of the signed operand. + IntRange signedRange = GetExprRange(S.Context, signedOperand); - // If the unsigned type is strictly smaller than the signed type, - // then (1) the result type will be signed and (2) the unsigned - // value will fit fully within the signed type, and thus the result - // of the comparison will be exact. - if (signedWidth > unsignedWidth) - return; + // Go ahead and analyze implicit conversions in the operands. Note + // that we skip the implicit conversions on both sides. + AnalyzeImplicitConversions(S, lex); + AnalyzeImplicitConversions(S, rex); - // Otherwise, calculate the effective ranges. - IntRange signedRange = GetExprRange(Context, signedOperand, signedWidth); - IntRange unsignedRange = GetExprRange(Context, unsignedOperand, unsignedWidth); - - // We should never be unable to prove that the unsigned operand is - // non-negative. - assert(unsignedRange.NonNegative && "unsigned range includes negative?"); - - // If the signed operand is non-negative, then the signed->unsigned - // conversion won't change it. - 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; - } + // If the signed range is non-negative, -Wsign-compare won't fire, + // but we should still check for comparisons which are always true + // or false. + if (signedRange.NonNegative) + return CheckTrivialUnsignedComparison(S, E); // 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 (BinOpc && - (*BinOpc == BinaryOperator::EQ || *BinOpc == BinaryOperator::NE) && - unsignedRange.Width < unsignedWidth) - return; + if (E->isEqualityOp()) { + unsigned comparisonWidth = S.Context.getIntWidth(T); + IntRange unsignedRange = GetExprRange(S.Context, unsignedOperand); + + // We should never be unable to prove that the unsigned operand is + // non-negative. + assert(unsignedRange.NonNegative && "unsigned range includes negative?"); + + if (unsignedRange.Width < comparisonWidth) + return; + } - Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison - : diag::warn_mixed_sign_conditional) - << lt << rt << lex->getSourceRange() << rex->getSourceRange(); + S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { +void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange(); } -/// Implements -Wconversion. -void Sema::CheckImplicitConversion(Expr *E, QualType T) { - // Don't diagnose in unevaluated contexts. - if (ExprEvalContexts.back().Context == Sema::Unevaluated) - return; +void CheckImplicitConversion(Sema &S, Expr *E, QualType T, + bool *ICContext = 0) { + if (E->isTypeDependent() || E->isValueDependent()) return; - // Don't diagnose for value-dependent expressions. - if (E->isValueDependent()) - return; - - const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr(); - const Type *Target = Context.getCanonicalType(T).getTypePtr(); + const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); + const Type *Target = S.Context.getCanonicalType(T).getTypePtr(); + if (Source == Target) return; + if (Target->isDependentType()) return; // Never diagnose implicit casts to bool. if (Target->isSpecificBuiltinType(BuiltinType::Bool)) @@ -2147,7 +2151,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { // Strip vector types. if (isa<VectorType>(Source)) { if (!isa<VectorType>(Target)) - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_vector_scalar); + return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar); Source = cast<VectorType>(Source)->getElementType().getTypePtr(); Target = cast<VectorType>(Target)->getElementType().getTypePtr(); @@ -2156,7 +2160,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { // Strip complex types. if (isa<ComplexType>(Source)) { if (!isa<ComplexType>(Target)) - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_complex_scalar); + return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar); Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); Target = cast<ComplexType>(Target)->getElementType().getTypePtr(); @@ -2176,15 +2180,15 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { // Don't warn about float constants that are precisely // representable in the target type. Expr::EvalResult result; - if (E->Evaluate(result, Context)) { + if (E->Evaluate(result, S.Context)) { // Value might be a float, a float vector, or a float complex. if (IsSameFloatAfterCast(result.Val, - Context.getFloatTypeSemantics(QualType(TargetBT, 0)), - Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) + S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), + S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) return; } - DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_precision); + DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision); } return; } @@ -2192,7 +2196,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { // If the target is integral, always warn. if ((TargetBT && TargetBT->isInteger())) // TODO: don't warn for integer values? - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_integer); + DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer); return; } @@ -2200,22 +2204,158 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { if (!Source->isIntegerType() || !Target->isIntegerType()) return; - IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType())); - IntRange TargetRange = IntRange::forCanonicalType(Context, Target); - - // FIXME: also signed<->unsigned? + IntRange SourceRange = GetExprRange(S.Context, E); + IntRange TargetRange = IntRange::forCanonicalType(S.Context, Target); if (SourceRange.Width > TargetRange.Width) { // People want to build with -Wshorten-64-to-32 and not -Wconversion // and by god we'll let them. if (SourceRange.Width == 64 && TargetRange.Width == 32) - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_64_32); - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_precision); + return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32); + return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision); + } + + if ((TargetRange.NonNegative && !SourceRange.NonNegative) || + (!TargetRange.NonNegative && SourceRange.NonNegative && + SourceRange.Width == TargetRange.Width)) { + unsigned DiagID = diag::warn_impcast_integer_sign; + + // Traditionally, gcc has warned about this under -Wsign-compare. + // We also want to warn about it in -Wconversion. + // So if -Wconversion is off, use a completely identical diagnostic + // in the sign-compare group. + // The conditional-checking code will + if (ICContext) { + DiagID = diag::warn_impcast_integer_sign_conditional; + *ICContext = true; + } + + return DiagnoseImpCast(S, E, T, DiagID); } return; } +void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T); + +void CheckConditionalOperand(Sema &S, Expr *E, QualType T, + bool &ICContext) { + E = E->IgnoreParenImpCasts(); + + if (isa<ConditionalOperator>(E)) + return CheckConditionalOperator(S, cast<ConditionalOperator>(E), T); + + AnalyzeImplicitConversions(S, E); + if (E->getType() != T) + return CheckImplicitConversion(S, E, T, &ICContext); + return; +} + +void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) { + AnalyzeImplicitConversions(S, E->getCond()); + + bool Suspicious = false; + CheckConditionalOperand(S, E->getTrueExpr(), T, Suspicious); + CheckConditionalOperand(S, E->getFalseExpr(), T, Suspicious); + + // If -Wconversion would have warned about either of the candidates + // for a signedness conversion to the context type... + if (!Suspicious) return; + + // ...but it's currently ignored... + if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional)) + return; + + // ...and -Wsign-compare isn't... + if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional)) + return; + + // ...then check whether it would have warned about either of the + // candidates for a signedness conversion to the condition type. + if (E->getType() != T) { + Suspicious = false; + CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), + E->getType(), &Suspicious); + if (!Suspicious) + CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), + E->getType(), &Suspicious); + if (!Suspicious) + return; + } + + // If so, emit a diagnostic under -Wsign-compare. + Expr *lex = E->getTrueExpr()->IgnoreParenImpCasts(); + Expr *rex = E->getFalseExpr()->IgnoreParenImpCasts(); + S.Diag(E->getQuestionLoc(), diag::warn_mixed_sign_conditional) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); +} + +/// AnalyzeImplicitConversions - Find and report any interesting +/// implicit conversions in the given expression. There are a couple +/// of competing diagnostics here, -Wconversion and -Wsign-compare. +void AnalyzeImplicitConversions(Sema &S, Expr *OrigE) { + QualType T = OrigE->getType(); + Expr *E = OrigE->IgnoreParenImpCasts(); + + // For conditional operators, we analyze the arguments as if they + // were being fed directly into the output. + if (isa<ConditionalOperator>(E)) { + ConditionalOperator *CO = cast<ConditionalOperator>(E); + CheckConditionalOperator(S, CO, T); + return; + } + + // Go ahead and check any implicit conversions we might have skipped. + // The non-canonical typecheck is just an optimization; + // CheckImplicitConversion will filter out dead implicit conversions. + if (E->getType() != T) + CheckImplicitConversion(S, E, T); + + // Now continue drilling into this expression. + + // Skip past explicit casts. + if (isa<ExplicitCastExpr>(E)) { + E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts(); + return AnalyzeImplicitConversions(S, E); + } + + // Do a somewhat different check with comparison operators. + if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isComparisonOp()) + return AnalyzeComparison(S, cast<BinaryOperator>(E)); + + // These break the otherwise-useful invariant below. Fortunately, + // we don't really need to recurse into them, because any internal + // expressions should have been analyzed already when they were + // built into statements. + if (isa<StmtExpr>(E)) return; + + // Don't descend into unevaluated contexts. + if (isa<SizeOfAlignOfExpr>(E)) return; + + // Now just recurse over the expression's children. + for (Stmt::child_iterator I = E->child_begin(), IE = E->child_end(); + I != IE; ++I) + AnalyzeImplicitConversions(S, cast<Expr>(*I)); +} + +} // end anonymous namespace + +/// Diagnoses "dangerous" implicit conversions within the given +/// expression (which is a full expression). Implements -Wconversion +/// and -Wsign-compare. +void Sema::CheckImplicitConversions(Expr *E) { + // Don't diagnose in unevaluated contexts. + if (ExprEvalContexts.back().Context == Sema::Unevaluated) + return; + + // Don't diagnose for value- or type-dependent expressions. + if (E->isTypeDependent() || E->isValueDependent()) + return; + + AnalyzeImplicitConversions(*this, E); +} + /// CheckParmsForFunctionDef - Check that the parameters of the given /// function are appropriate for the definition of a function. This /// takes care of any checks that cannot be performed on the diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index c075d161704e..d8c1a5cd7e3e 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -127,6 +127,13 @@ namespace { explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0) : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { } + /// \brief Whether we should include code patterns in the completion + /// results. + bool includeCodePatterns() const { + return SemaRef.CodeCompleter && + SemaRef.CodeCompleter->includeCodePatterns(); + } + /// \brief Set the filter used for code-completion results. void setFilter(LookupFilter Filter) { this->Filter = Filter; @@ -532,8 +539,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. - if (AsNestedNameSpecifier) + if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; + R.Priority = CCP_NestedNameSpecifier; + } // If this result is supposed to have an informative qualifier, add one. if (R.QualifierIsInformative && !R.Qualifier && @@ -581,8 +590,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. - if (AsNestedNameSpecifier) + if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; + R.Priority = CCP_NestedNameSpecifier; + } else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass && isa<CXXRecordDecl>(R.Declaration->getDeclContext() ->getLookupContext())) @@ -601,6 +612,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, R.QualifierIsInformative = false; } + // Adjust the priority if this result comes from a base class. + if (InBaseClass) + R.Priority += CCD_InBaseClass; + // Insert this result into the set of results. Results.push_back(R); } @@ -672,8 +687,8 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const { ND = ClassTemplate->getTemplatedDecl(); if (RecordDecl *RD = dyn_cast<RecordDecl>(ND)) - return RD->getTagKind() == TagDecl::TK_class || - RD->getTagKind() == TagDecl::TK_struct; + return RD->getTagKind() == TTK_Class || + RD->getTagKind() == TTK_Struct; return false; } @@ -685,7 +700,7 @@ bool ResultBuilder::IsUnion(NamedDecl *ND) const { ND = ClassTemplate->getTemplatedDecl(); if (RecordDecl *RD = dyn_cast<RecordDecl>(ND)) - return RD->getTagKind() == TagDecl::TK_union; + return RD->getTagKind() == TTK_Union; return false; } @@ -744,47 +759,56 @@ namespace { static void AddTypeSpecifierResults(const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; - Results.AddResult(Result("short")); - Results.AddResult(Result("long")); - Results.AddResult(Result("signed")); - Results.AddResult(Result("unsigned")); - Results.AddResult(Result("void")); - Results.AddResult(Result("char")); - Results.AddResult(Result("int")); - Results.AddResult(Result("float")); - Results.AddResult(Result("double")); - Results.AddResult(Result("enum")); - Results.AddResult(Result("struct")); - Results.AddResult(Result("union")); - Results.AddResult(Result("const")); - Results.AddResult(Result("volatile")); + Results.AddResult(Result("short", CCP_Type)); + Results.AddResult(Result("long", CCP_Type)); + Results.AddResult(Result("signed", CCP_Type)); + Results.AddResult(Result("unsigned", CCP_Type)); + Results.AddResult(Result("void", CCP_Type)); + Results.AddResult(Result("char", CCP_Type)); + Results.AddResult(Result("int", CCP_Type)); + Results.AddResult(Result("float", CCP_Type)); + Results.AddResult(Result("double", CCP_Type)); + Results.AddResult(Result("enum", CCP_Type)); + Results.AddResult(Result("struct", CCP_Type)); + Results.AddResult(Result("union", CCP_Type)); + Results.AddResult(Result("const", CCP_Type)); + Results.AddResult(Result("volatile", CCP_Type)); if (LangOpts.C99) { // C99-specific - Results.AddResult(Result("_Complex")); - Results.AddResult(Result("_Imaginary")); - Results.AddResult(Result("_Bool")); - Results.AddResult(Result("restrict")); + Results.AddResult(Result("_Complex", CCP_Type)); + Results.AddResult(Result("_Imaginary", CCP_Type)); + Results.AddResult(Result("_Bool", CCP_Type)); + Results.AddResult(Result("restrict", CCP_Type)); } if (LangOpts.CPlusPlus) { // C++-specific - Results.AddResult(Result("bool")); - Results.AddResult(Result("class")); - Results.AddResult(Result("wchar_t")); + Results.AddResult(Result("bool", CCP_Type)); + Results.AddResult(Result("class", CCP_Type)); + Results.AddResult(Result("wchar_t", CCP_Type)); + + if (Results.includeCodePatterns()) { + // typename qualified-id + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typename"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Results.AddResult(Result(Pattern)); + } - // typename qualified-id - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typename"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("qualified-id"); - Results.AddResult(Result(Pattern)); - if (LangOpts.CPlusPlus0x) { - Results.AddResult(Result("auto")); - Results.AddResult(Result("char16_t")); - Results.AddResult(Result("char32_t")); - Results.AddResult(Result("decltype")); + Results.AddResult(Result("auto", CCP_Type)); + Results.AddResult(Result("char16_t", CCP_Type)); + Results.AddResult(Result("char32_t", CCP_Type)); + if (Results.includeCodePatterns()) { + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("decltype"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + } } } @@ -795,12 +819,14 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, // Results.AddResult(Result("_Decimal64")); // Results.AddResult(Result("_Decimal128")); - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typeof"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression-or-type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + } } } @@ -843,6 +869,7 @@ static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC, case Action::CCC_Statement: case Action::CCC_ForInit: case Action::CCC_Condition: + case Action::CCC_RecoveryInFunction: break; } } @@ -868,7 +895,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, typedef CodeCompleteConsumer::Result Result; switch (CCC) { case Action::CCC_Namespace: - if (SemaRef.getLangOptions().CPlusPlus) { + if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { // namespace <identifier> { } CodeCompletionString *Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("namespace"); @@ -920,8 +947,10 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, // Fall through case Action::CCC_Class: - Results.AddResult(Result("typedef")); - if (SemaRef.getLangOptions().CPlusPlus) { + if (Results.includeCodePatterns()) + Results.AddResult(Result("typedef")); + + if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { // Using declaration CodeCompletionString *Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("using"); @@ -964,7 +993,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, case Action::CCC_Template: case Action::CCC_MemberTemplate: - if (SemaRef.getLangOptions().CPlusPlus) { + if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { // template < parameters > CodeCompletionString *Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("template"); @@ -994,11 +1023,13 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true); break; + case Action::CCC_RecoveryInFunction: case Action::CCC_Statement: { - Results.AddResult(Result("typedef")); + if (Results.includeCodePatterns()) + Results.AddResult(Result("typedef")); CodeCompletionString *Pattern = 0; - if (SemaRef.getLangOptions().CPlusPlus) { + if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("try"); Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); @@ -1018,37 +1049,39 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, if (SemaRef.getLangOptions().ObjC1) AddObjCStatementResults(Results, true); - // if (condition) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("if"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - if (SemaRef.getLangOptions().CPlusPlus) - Pattern->AddPlaceholderChunk("condition"); - else - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); - - // switch (condition) { } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("switch"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - if (SemaRef.getLangOptions().CPlusPlus) - Pattern->AddPlaceholderChunk("condition"); - else - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + // if (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("if"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + // switch (condition) { } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("switch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + } + // Switch-specific statements. - if (!SemaRef.getSwitchStack().empty()) { + if (!SemaRef.getSwitchStack().empty() && Results.includeCodePatterns()) { // case expression: Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("case"); @@ -1063,52 +1096,54 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Results.AddResult(Result(Pattern)); } - /// while (condition) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("while"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - if (SemaRef.getLangOptions().CPlusPlus) - Pattern->AddPlaceholderChunk("condition"); - else - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + /// while (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); - // do { statements } while ( expression ); - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("do"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Pattern->AddTextChunk("while"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // do { statements } while ( expression ); + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("do"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // for ( for-init-statement ; condition ; expression ) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("for"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99) - Pattern->AddPlaceholderChunk("init-statement"); - else - Pattern->AddPlaceholderChunk("init-expression"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); - Pattern->AddPlaceholderChunk("condition"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); - Pattern->AddPlaceholderChunk("inc-expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + // for ( for-init-statement ; condition ; expression ) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("for"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99) + Pattern->AddPlaceholderChunk("init-statement"); + else + Pattern->AddPlaceholderChunk("init-expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("condition"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("inc-expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + } if (S->getContinueParent()) { // continue ; @@ -1143,21 +1178,23 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, } Results.AddResult(Result(Pattern)); - // goto identifier ; - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("goto"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("identifier"); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + // goto identifier ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("goto"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Results.AddResult(Result(Pattern)); - // Using directives - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("using"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("namespace"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("identifier"); - Results.AddResult(Result(Pattern)); + // Using directives + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Results.AddResult(Result(Pattern)); + } } // Fall through (for statement expressions). @@ -1178,103 +1215,107 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Results.AddResult(Result("true")); Results.AddResult(Result("false")); - // dynamic_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("dynamic_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); - - // static_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("static_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); - - // reinterpret_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("reinterpret_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + // dynamic_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("dynamic_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // static_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("static_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // const_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("const_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // reinterpret_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("reinterpret_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // typeid ( expression-or-type ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typeid"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression-or-type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // const_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("const_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // new T ( ... ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("new"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expressions"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // typeid ( expression-or-type ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeid"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // new T [ ] ( ... ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("new"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); - Pattern->AddPlaceholderChunk("size"); - Pattern->AddChunk(CodeCompletionString::CK_RightBracket); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expressions"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // new T ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // delete expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("delete"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + // new T [ ] ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddPlaceholderChunk("size"); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // delete expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); - // delete [] expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("delete"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); - Pattern->AddChunk(CodeCompletionString::CK_RightBracket); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + // delete [] expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); - // throw expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("throw"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + // throw expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("throw"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); + } + + // FIXME: Rethrow? } if (SemaRef.getLangOptions().ObjC1) { @@ -1286,13 +1327,15 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, AddObjCExpressionResults(Results, true); } - // sizeof expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("sizeof"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression-or-type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + // sizeof expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("sizeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + } break; } } @@ -1543,7 +1586,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { return Result; } - assert(Kind == RK_Declaration && "Missed a macro kind?"); + assert(Kind == RK_Declaration && "Missed a result kind?"); NamedDecl *ND = Declaration; if (StartsNestedNameSpecifier) { @@ -1925,6 +1968,10 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, case CCC_Condition: Results.setFilter(&ResultBuilder::IsOrdinaryName); break; + + case CCC_RecoveryInFunction: + // Unfiltered + break; } CodeCompletionDeclConsumer Consumer(Results, CurContext); @@ -2047,14 +2094,14 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, I != E; ++I) AddObjCProperties(*I, true, CurContext, Results); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || - (!IsArrow && BaseType->isObjCInterfaceType())) { + (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. ObjCInterfaceDecl *Class = 0; if (const ObjCObjectPointerType *ObjCPtr = BaseType->getAs<ObjCObjectPointerType>()) Class = ObjCPtr->getInterfaceDecl(); else - Class = BaseType->getAs<ObjCInterfaceType>()->getDecl(); + Class = BaseType->getAs<ObjCObjectType>()->getInterface(); // Add all ivars from this class and its superclasses. if (Class) { @@ -2413,6 +2460,9 @@ void Sema::CodeCompleteOperatorName(Scope *S) { static void AddObjCImplementationResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; // Since we have an implementation, we can end it. Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end))); @@ -2438,6 +2488,9 @@ static void AddObjCImplementationResults(const LangOptions &LangOpts, static void AddObjCInterfaceResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; // Since we have an interface or protocol, we can end it. @@ -2456,6 +2509,9 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts, } static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; CodeCompletionString *Pattern = 0; @@ -2515,6 +2571,9 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, } static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; CodeCompletionString *Pattern = 0; @@ -2544,6 +2603,9 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { } static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; CodeCompletionString *Pattern = 0; @@ -2590,6 +2652,9 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { static void AddObjCVisibilityResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private))); Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected))); @@ -2911,9 +2976,9 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { ObjCInterfaceDecl *IFace = 0; switch (Msg->getReceiverKind()) { case ObjCMessageExpr::Class: - if (const ObjCInterfaceType *IFaceType - = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()) - IFace = IFaceType->getDecl(); + if (const ObjCObjectType *ObjType + = Msg->getClassReceiver()->getAs<ObjCObjectType>()) + IFace = ObjType->getInterface(); break; case ObjCMessageExpr::Instance: { @@ -2994,9 +3059,9 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) { // "super" names an interface. Use it. } else if (TypeDecl *TD = dyn_cast_or_null<TypeDecl>(ND)) { - if (const ObjCInterfaceType *Iface - = Context.getTypeDeclType(TD)->getAs<ObjCInterfaceType>()) - CDecl = Iface->getDecl(); + if (const ObjCObjectType *Iface + = Context.getTypeDeclType(TD)->getAs<ObjCObjectType>()) + CDecl = Iface->getInterface(); } else if (ND && isa<UnresolvedUsingTypenameDecl>(ND)) { // "super" names an unresolved type; we can't be more specific. } else { @@ -3030,8 +3095,8 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, if (Receiver) { QualType T = GetTypeFromParser(Receiver, 0); if (!T.isNull()) - if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>()) - CDecl = Interface->getDecl(); + if (const ObjCObjectType *Interface = T->getAs<ObjCObjectType>()) + CDecl = Interface->getInterface(); } // Add all of the factory methods in this Objective-C class, its protocols, @@ -3079,8 +3144,6 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, } Results.ExitScope(); - - // This also suppresses remaining diagnostics. HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a802679b26e1..af020990dda5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -90,8 +90,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // We know from the grammar that this name refers to a type, so build a // DependentNameType node to describe the type. return CheckTypenameType(ETK_None, - (NestedNameSpecifier *)SS->getScopeRep(), - II, SS->getRange()).getAsOpaquePtr(); + (NestedNameSpecifier *)SS->getScopeRep(), II, + SourceLocation(), SS->getRange(), NameLoc + ).getAsOpaquePtr(); } return 0; @@ -191,7 +192,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, T = Context.getTypeDeclType(TD); if (SS) - T = getQualifiedNameType(*SS, T); + T = getElaboratedType(ETK_None, *SS, T); } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { T = Context.getObjCInterfaceType(IDecl); @@ -223,10 +224,11 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { if (R.getResultKind() == LookupResult::Found) if (const TagDecl *TD = R.getAsSingle<TagDecl>()) { switch (TD->getTagKind()) { - case TagDecl::TK_struct: return DeclSpec::TST_struct; - case TagDecl::TK_union: return DeclSpec::TST_union; - case TagDecl::TK_class: return DeclSpec::TST_class; - case TagDecl::TK_enum: return DeclSpec::TST_enum; + default: return DeclSpec::TST_unspecified; + case TTK_Struct: return DeclSpec::TST_struct; + case TTK_Union: return DeclSpec::TST_union; + case TTK_Class: return DeclSpec::TST_class; + case TTK_Enum: return DeclSpec::TST_enum; } } @@ -285,8 +287,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, Name.setIdentifier(&II, IILoc); CXXScopeSpec EmptySS; TemplateTy TemplateResult; - if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult) - == TNK_Type_template) { + bool MemberOfUnknownSpecialization; + if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult, + MemberOfUnknownSpecialization) == TNK_Type_template) { TemplateName TplName = TemplateResult.getAsVal<TemplateName>(); Diag(IILoc, diag::err_template_missing_args) << TplName; if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) { @@ -544,9 +547,9 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return false; } - // If we failed to complete the type for some reason, don't - // diagnose the variable. - if (Ty->isIncompleteType()) + // If we failed to complete the type for some reason, or if the type is + // dependent, don't diagnose the variable. + if (Ty->isIncompleteType() || Ty->isDependentType()) return false; if (const TagType *TT = Ty->getAs<TagType>()) { @@ -555,9 +558,10 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return false; if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) { - if (!RD->hasTrivialConstructor()) - return false; - if (!RD->hasTrivialDestructor()) + // FIXME: Checking for the presence of a user-declared constructor + // isn't completely accurate; we'd prefer to check that the initializer + // has no side effects. + if (RD->hasUserDeclaredConstructor() || !RD->hasTrivialDestructor()) return false; } } @@ -568,6 +572,18 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return true; } +void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { + if (!ShouldDiagnoseUnusedDecl(D)) + return; + + if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) + Diag(D->getLocation(), diag::warn_unused_exception_param) + << D->getDeclName(); + else + Diag(D->getLocation(), diag::warn_unused_variable) + << D->getDeclName(); +} + void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (S->decl_empty()) return; assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && @@ -584,15 +600,9 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. - if (ShouldDiagnoseUnusedDecl(D) && - S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) { - if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) - Diag(D->getLocation(), diag::warn_unused_exception_param) - << D->getDeclName(); - else - Diag(D->getLocation(), diag::warn_unused_variable) - << D->getDeclName(); - } + if (S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) + DiagnoseUnusedDecl(D); + // Remove this name from our lexical scope. IdResolver.RemoveDecl(D); } @@ -1069,10 +1079,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { = cast<FunctionType>(OldQType.getTypePtr())->getResultType(); QualType NewReturnType = cast<FunctionType>(NewQType.getTypePtr())->getResultType(); + QualType ResQT; if (OldReturnType != NewReturnType) { - Diag(New->getLocation(), diag::err_ovl_diff_return_type); - Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); - return true; + if (NewReturnType->isObjCObjectPointerType() + && OldReturnType->isObjCObjectPointerType()) + ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); + if (ResQT.isNull()) { + Diag(New->getLocation(), diag::err_ovl_diff_return_type); + Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); + return true; + } + else + NewQType = ResQT; } const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); @@ -1356,6 +1374,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { = Context.getCanonicalType(New->getType())->getAs<ArrayType>(); if (OldArray->getElementType() == NewArray->getElementType()) MergedT = Old->getType(); + } else if (New->getType()->isObjCObjectPointerType() + && Old->getType()->isObjCObjectPointerType()) { + MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); } } else { MergedT = Context.mergeTypes(New->getType(), Old->getType()); @@ -1435,7 +1456,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. -Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { +Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS) { // FIXME: Error on auto/register at file scope // FIXME: Error on inline/virtual/explicit // FIXME: Warn on useless __thread @@ -1485,7 +1507,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOptions().CPlusPlus || Record->getDeclContext()->isRecord()) - return BuildAnonymousStructOrUnion(S, DS, Record); + return BuildAnonymousStructOrUnion(S, DS, AS, Record); Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); @@ -1563,8 +1585,10 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, /// /// This routine is recursive, injecting the names of nested anonymous /// structs/unions into the owning context and scope as well. -bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, - RecordDecl *AnonRecord) { +static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, + DeclContext *Owner, + RecordDecl *AnonRecord, + AccessSpecifier AS) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl : diag::err_anonymous_struct_member_redecl; @@ -1574,7 +1598,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(), + if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, (*F)->getDeclName(), (*F)->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be @@ -1588,15 +1612,19 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, // considered to have been defined in the scope in which the // anonymous union is declared. Owner->makeDeclVisibleInContext(*F); - S->AddDecl(DeclPtrTy::make(*F)); - IdResolver.AddDecl(*F); + S->AddDecl(Sema::DeclPtrTy::make(*F)); + SemaRef.IdResolver.AddDecl(*F); + + // That includes picking up the appropriate access specifier. + if (AS != AS_none) (*F)->setAccess(AS); } } else if (const RecordType *InnerRecordType = (*F)->getType()->getAs<RecordType>()) { RecordDecl *InnerRecord = InnerRecordType->getDecl(); if (InnerRecord->isAnonymousStructOrUnion()) Invalid = Invalid || - InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord); + InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner, + InnerRecord, AS); } } @@ -1666,6 +1694,7 @@ StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec, /// (C++ [class.union]) and a GNU C extension; anonymous structures /// are a GNU C and GNU C++ extension. Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, RecordDecl *Record) { DeclContext *Owner = Record->getDeclContext(); @@ -1720,7 +1749,8 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // C++ [class.union]p3: // An anonymous union shall not have private or protected // members (clause 11). - if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) { + assert(FD->getAccess() != AS_none); + if (FD->getAccess() != AS_public) { Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member) << (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected); Invalid = true; @@ -1777,7 +1807,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/0, /*Mutable=*/false); - Anon->setAccess(AS_public); + Anon->setAccess(AS); if (getLangOptions().CPlusPlus) { FieldCollector->Add(cast<FieldDecl>(Anon)); if (!cast<CXXRecordDecl>(Record)->isEmpty()) @@ -1814,7 +1844,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. - if (InjectAnonymousStructOrUnionMembers(S, Owner, Record)) + if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS)) Invalid = true; // Mark this as an anonymous struct/union type. Note that we do not @@ -2711,7 +2741,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, QualType T = NewVD->getType(); - if (T->isObjCInterfaceType()) { + if (T->isObjCObjectType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object); return NewVD->setInvalidDecl(); } @@ -2929,7 +2959,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.setInvalidType(); // Do not allow returning a objc interface by-value. - if (R->getAs<FunctionType>()->getResultType()->isObjCInterfaceType()) { + if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { Diag(D.getIdentifierLoc(), diag::err_object_cannot_be_passed_returned_by_value) << 0 << R->getAs<FunctionType>()->getResultType(); @@ -4322,7 +4352,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, // Parameter declarators cannot be interface types. All ObjC objects are // passed by reference. - if (T->isObjCInterfaceType()) { + if (T->isObjCObjectType()) { Diag(NameLoc, diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; New->setInvalidDecl(); @@ -4540,6 +4570,38 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { return DeclPtrTy::make(FD); } +/// \brief Given the set of return statements within a function body, +/// compute the variables that are subject to the named return value +/// optimization. +/// +/// Each of the variables that is subject to the named return value +/// optimization will be marked as NRVO variables in the AST, and any +/// return statement that has a marked NRVO variable as its NRVO candidate can +/// use the named return value optimization. +/// +/// This function applies a very simplistic algorithm for NRVO: if every return +/// statement in the function has the same NRVO candidate, that candidate is +/// the NRVO variable. +/// +/// FIXME: Employ a smarter algorithm that accounts for multiple return +/// statements and the lifetimes of the NRVO candidates. We should be able to +/// find a maximal set of NRVO variables. +static void ComputeNRVO(Stmt *Body, ReturnStmt **Returns, unsigned NumReturns) { + const VarDecl *NRVOCandidate = 0; + for (unsigned I = 0; I != NumReturns; ++I) { + if (!Returns[I]->getNRVOCandidate()) + return; + + if (!NRVOCandidate) + NRVOCandidate = Returns[I]->getNRVOCandidate(); + else if (NRVOCandidate != Returns[I]->getNRVOCandidate()) + return; + } + + if (NRVOCandidate) + const_cast<VarDecl*>(NRVOCandidate)->setNRVOVariable(true); +} + Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) { return ActOnFinishFunctionBody(D, move(BodyArg), false); } @@ -4567,12 +4629,17 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, WP.disableCheckFallThrough(); } - if (!FD->isInvalidDecl()) + if (!FD->isInvalidDecl()) { DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); - - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) - MaybeMarkVirtualMembersReferenced(Method->getLocation(), Method); - + + // If this is a constructor, we need a vtable. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD)) + MarkVTableUsed(FD->getLocation(), Constructor->getParent()); + + ComputeNRVO(Body, FunctionScopes.back()->Returns.data(), + FunctionScopes.back()->Returns.size()); + } + assert(FD == getCurFunctionDecl() && "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); @@ -4636,7 +4703,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // Verify that that gotos and switch cases don't jump into scopes illegally. // Verify that that gotos and switch cases don't jump into scopes illegally. - if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction()) + if (FunctionNeedsScopeChecking() && + !dcl->isInvalidDecl() && + !hasAnyErrorsInThisFunction()) DiagnoseInvalidJumps(Body); if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) @@ -4838,38 +4907,38 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, /// /// \returns true if the new tag kind is acceptable, false otherwise. bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, - TagDecl::TagKind NewTag, + TagTypeKind NewTag, SourceLocation NewTagLoc, const IdentifierInfo &Name) { // C++ [dcl.type.elab]p3: // The class-key or enum keyword present in the // elaborated-type-specifier shall agree in kind with the - // declaration to which the name in theelaborated-type-specifier + // declaration to which the name in the elaborated-type-specifier // refers. This rule also applies to the form of // elaborated-type-specifier that declares a class-name or // friend class since it can be construed as referring to the // definition of the class. Thus, in any // elaborated-type-specifier, the enum keyword shall be used to - // refer to an enumeration (7.2), the union class-keyshall be + // refer to an enumeration (7.2), the union class-key shall be // used to refer to a union (clause 9), and either the class or // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. - TagDecl::TagKind OldTag = Previous->getTagKind(); + TagTypeKind OldTag = Previous->getTagKind(); if (OldTag == NewTag) return true; - if ((OldTag == TagDecl::TK_struct || OldTag == TagDecl::TK_class) && - (NewTag == TagDecl::TK_struct || NewTag == TagDecl::TK_class)) { + if ((OldTag == TTK_Struct || OldTag == TTK_Class) && + (NewTag == TTK_Struct || NewTag == TTK_Class)) { // Warn about the struct/class tag mismatch. bool isTemplate = false; if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous)) isTemplate = Record->getDescribedClassTemplate(); Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << (NewTag == TagDecl::TK_class) + << (NewTag == TTK_Class) << isTemplate << &Name << FixItHint::CreateReplacement(SourceRange(NewTagLoc), - OldTag == TagDecl::TK_class? "class" : "struct"); + OldTag == TTK_Class? "class" : "struct"); Diag(Previous->getLocation(), diag::note_previous_use); return true; } @@ -4891,7 +4960,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, "Nameless record must be a definition!"); OwnedDecl = false; - TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec); + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); // FIXME: Check explicit specializations more carefully. bool isExplicitSpecialization = false; @@ -4915,7 +4984,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } else { // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) - << ElaboratedType::getNameForTagKind(Kind) << Name; + << TypeWithKeyword::getTagTypeKindName(Kind) << Name; isExplicitSpecialization = true; } } @@ -5134,8 +5203,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // struct or something similar. if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) { bool SafeToContinue - = (PrevTagDecl->getTagKind() != TagDecl::TK_enum && - Kind != TagDecl::TK_enum); + = (PrevTagDecl->getTagKind() != TTK_Enum && + Kind != TTK_Enum); if (SafeToContinue) Diag(KWLoc, diag::err_use_with_wrong_tag) << Name @@ -5289,7 +5358,7 @@ CreateNewDecl: // PrevDecl. TagDecl *New; - if (Kind == TagDecl::TK_enum) { + if (Kind == TTK_Enum) { // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // enum X { A, B, C } D; D should chain to X. New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc, @@ -5319,16 +5388,18 @@ CreateNewDecl: // Maybe add qualifier info. if (SS.isNotEmpty()) { - NestedNameSpecifier *NNS - = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); - New->setQualifierInfo(NNS, SS.getRange()); + if (SS.isSet()) { + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + New->setQualifierInfo(NNS, SS.getRange()); + } + else + Invalid = true; } - 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 - // attributes are checked when the ASTContext lays out the - // structure. + if (RecordDecl *RD = dyn_cast<RecordDecl>(New)) { + // Add alignment attributes if necessary; these attributes are checked when + // the ASTContext lays out the structure. // // It is important for implementing the correct semantics that this // happen here (in act on tag decl). The #pragma pack stack is @@ -5336,15 +5407,14 @@ CreateNewDecl: // many points during the parsing of a struct declaration (because // the #pragma tokens are effectively skipped over during the // parsing of the struct). - if (unsigned Alignment = getPragmaPackAlignment()) - New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8)); + AddAlignmentAttributesForRecord(RD); } // If this is a specialization of a member class (of a class template), // check the specialization. if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) Invalid = true; - + if (Invalid) New->setInvalidDecl(); @@ -5439,37 +5509,6 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD, "Broken injected-class-name"); } -// Traverses the class and any nested classes, making a note of any -// dynamic classes that have no key function so that we can mark all of -// their virtual member functions as "used" at the end of the translation -// unit. This ensures that all functions needed by the vtable will get -// instantiated/synthesized. -static void -RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record, - SourceLocation Loc) { - // We don't look at dependent or undefined classes. - if (Record->isDependentContext() || !Record->isDefinition()) - return; - - if (Record->isDynamicClass()) { - const CXXMethodDecl *KeyFunction = S.Context.getKeyFunction(Record); - - if (!KeyFunction) - S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, - Loc)); - - if ((!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined())) - && Record->getLinkage() == ExternalLinkage) - S.Diag(Record->getLocation(), diag::warn_weak_vtable) << Record; - } - for (DeclContext::decl_iterator D = Record->decls_begin(), - DEnd = Record->decls_end(); - D != DEnd; ++D) { - if (CXXRecordDecl *Nested = dyn_cast<CXXRecordDecl>(*D)) - RecordDynamicClassesWithNoKeyFunction(S, Nested, Loc); - } -} - void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, SourceLocation RBraceLoc) { AdjustDeclIfTemplate(TagD); @@ -5481,10 +5520,6 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, // Exit this scope of this tag's definition. PopDeclContext(); - - if (isa<CXXRecordDecl>(Tag) && !Tag->getLexicalDeclContext()->isRecord()) - RecordDynamicClassesWithNoKeyFunction(*this, cast<CXXRecordDecl>(Tag), - RBraceLoc); // Notify the consumer that we've defined a tag. Consumer.HandleTagDeclDefinition(Tag); @@ -6098,6 +6133,15 @@ void Sema::ActOnFields(Scope* S, EnclosingDecl->setInvalidDecl(); continue; } + if (!FD->getType()->isDependentType() && + !Context.getBaseElementType(FD->getType())->isPODType()) { + Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type) + << FD->getDeclName() << FD->getType(); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // Okay, we have a legal flexible array member at the end of the struct. if (Record) Record->setHasFlexibleArrayMember(true); @@ -6132,7 +6176,7 @@ void Sema::ActOnFields(Scope* S, } if (Record && FDTTy->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); - } else if (FDTy->isObjCInterfaceType()) { + } else if (FDTy->isObjCObjectType()) { /// A field cannot be an Objective-c object Diag(FD->getLocation(), diag::err_statically_allocated_object); FD->setInvalidDecl(); @@ -6435,7 +6479,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(EnumType); } - Enum->completeDefinition(Context.DependentTy, Context.DependentTy); + Enum->completeDefinition(Context.DependentTy, Context.DependentTy, 0, 0); return; } @@ -6616,7 +6660,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(NewTy); } - Enum->completeDefinition(BestType, BestPromotionType); + Enum->completeDefinition(BestType, BestPromotionType, + NumPositiveBits, NumNegativeBits); } Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 90aa9c1c130d..c6dcc3b97b2a 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -129,11 +129,11 @@ static inline bool isNSStringType(QualType T, ASTContext &Ctx) { if (!PT) return false; - const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAs<ObjCInterfaceType>(); - if (!ClsT) + ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); + if (!Cls) return false; - IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier(); + IdentifierInfo* ClsName = Cls->getIdentifier(); // FIXME: Should we walk the chain of classes? return ClsName == &Ctx.Idents.get("NSString") || @@ -150,7 +150,7 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return false; const RecordDecl *RD = RT->getDecl(); - if (RD->getTagKind() != TagDecl::TK_struct) + if (RD->getTagKind() != TTK_Struct) return false; return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); @@ -259,6 +259,26 @@ static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); } +static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, + Sema &S) { + + // The iboutletcollection attribute can have zero or one arguments. + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + // The IBOutletCollection attributes only apply to instance variables of + // Objective-C classes. + if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) { + S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); + return; + } + + // FIXME: Eventually accept the type argument. + d->addAttr(::new (S.Context) IBOutletCollectionAttr()); +} + static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // GCC ignores the nonnull attribute on K&R style function prototypes, so we // ignore it as well @@ -280,7 +300,8 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // The argument must be an integer constant expression. Expr *Ex = static_cast<Expr *>(*I); llvm::APSInt ArgNum(32); - if (!Ex->isIntegerConstantExpr(ArgNum, S.Context)) { + if (Ex->isTypeDependent() || Ex->isValueDependent() || + !Ex->isIntegerConstantExpr(ArgNum, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "nonnull" << Ex->getSourceRange(); return; @@ -560,7 +581,8 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() > 0) { Expr *E = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!E->isIntegerConstantExpr(Idx, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "constructor" << 1 << E->getSourceRange(); return; @@ -589,7 +611,8 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() > 0) { Expr *E = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!E->isIntegerConstantExpr(Idx, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "destructor" << 1 << E->getSourceRange(); return; @@ -745,7 +768,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() > 0) { Expr *E = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!E->isIntegerConstantExpr(Idx, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "sentinel" << 1 << E->getSourceRange(); return; @@ -763,7 +787,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() > 1) { Expr *E = static_cast<Expr *>(Attr.getArg(1)); llvm::APSInt Idx(32); - if (!E->isIntegerConstantExpr(Idx, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "sentinel" << 2 << E->getSourceRange(); return; @@ -924,7 +949,8 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr, for (unsigned i = 0; i < 3; ++i) { Expr *E = static_cast<Expr *>(Attr.getArg(i)); llvm::APSInt ArgNum(32); - if (!E->isIntegerConstantExpr(ArgNum, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(ArgNum, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "reqd_work_group_size" << E->getSourceRange(); return; @@ -1076,7 +1102,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { // checks for the 2nd argument Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { + if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || + !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "format" << 2 << IdxExpr->getSourceRange(); return; @@ -1198,7 +1225,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // checks for the 2nd argument Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { + if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || + !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "format" << 2 << IdxExpr->getSourceRange(); return; @@ -1261,7 +1289,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the 3rd argument Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1)); llvm::APSInt FirstArg(32); - if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) { + if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() || + !FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "format" << 3 << FirstArgExpr->getSourceRange(); return; @@ -1403,7 +1432,8 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Alignment(32); - if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) { + if (alignmentExpr->isTypeDependent() || alignmentExpr->isValueDependent() || + !alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "aligned" << alignmentExpr->getSourceRange(); return; @@ -1654,6 +1684,8 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) { case AttributeList::AT_stdcall: d->addAttr(::new (S.Context) StdCallAttr()); return; + case AttributeList::AT_thiscall: + d->addAttr(::new (S.Context) ThisCallAttr()); case AttributeList::AT_cdecl: d->addAttr(::new (S.Context) CDeclAttr()); return; @@ -1678,7 +1710,8 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) { Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt NumParams(32); - if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { + if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() || + !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "regparm" << NumParamsExpr->getSourceRange(); return; @@ -1871,7 +1904,9 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, return; switch (Attr.getKind()) { case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break; - case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; + case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; + case AttributeList::AT_IBOutletCollection: + HandleIBOutletCollection(D, Attr, S); break; case AttributeList::AT_address_space: case AttributeList::AT_objc_gc: case AttributeList::AT_vector_size: @@ -1950,6 +1985,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_stdcall: case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: + case AttributeList::AT_thiscall: HandleCallConvAttr(D, Attr, S); break; default: diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b9c7d7948f2c..148d1463c201 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -461,7 +461,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, if (BaseType->isDependentType()) return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, - Class->getTagKind() == RecordDecl::TK_class, + Class->getTagKind() == TTK_Class, Access, BaseType); // Base specifiers must be record types. @@ -504,9 +504,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual); // Create the base specifier. - // FIXME: Allocate via ASTContext? return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, - Class->getTagKind() == RecordDecl::TK_class, + Class->getTagKind() == TTK_Class, Access, BaseType); } @@ -623,7 +622,13 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, QualType NewBaseType = Context.getCanonicalType(Bases[idx]->getType()); NewBaseType = NewBaseType.getLocalUnqualifiedType(); - + if (!Class->hasObjectMember()) { + if (const RecordType *FDTTy = + NewBaseType.getTypePtr()->getAs<RecordType>()) + if (FDTTy->getDecl()->hasObjectMember()) + Class->setHasObjectMember(true); + } + if (KnownBaseTypes[NewBaseType]) { // C++ [class.mi]p3: // A class shall not be specified as a direct base class of a @@ -736,6 +741,18 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths, BasePathArray.push_back(Path[I].Base); } +/// \brief Determine whether the given base path includes a virtual +/// base class. +bool Sema::BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath) { + for (CXXBaseSpecifierArray::iterator B = BasePath.begin(), + BEnd = BasePath.end(); + B != BEnd; ++B) + if ((*B)->isVirtual()) + return true; + + return false; +} + /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base /// conversion (where Derived and Base are class types) is /// well-formed, meaning that the conversion is unambiguous (and @@ -1125,7 +1142,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // specialization, we take it as a type name. BaseType = CheckTypenameType(ETK_None, (NestedNameSpecifier *)SS.getScopeRep(), - *MemberOrBase, SS.getRange()); + *MemberOrBase, SourceLocation(), + SS.getRange(), IdLoc); if (BaseType.isNull()) return true; @@ -1192,7 +1210,7 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, static_cast<NestedNameSpecifier*>(SS.getScopeRep()); // FIXME: preserve source range information - BaseType = Context.getQualifiedNameType(Qualifier, BaseType); + BaseType = Context.getElaboratedType(ETK_None, Qualifier, BaseType); } } } @@ -1357,7 +1375,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); - SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin(); + SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (BaseType->isDependentType() || HasDependentArg) { // Can't check initialization for a base of dependent type or when // any of the arguments are type-dependent expressions. @@ -1381,7 +1399,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (!BaseType->isRecordType()) return Diag(BaseLoc, diag::err_base_init_does_not_name_class) - << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); + << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); // C++ [class.base.init]p2: // [...] Unless the mem-initializer-id names a nonstatic data @@ -1402,7 +1420,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // class, the mem-initializer is ill-formed. if (DirectBaseSpec && VirtualBaseSpec) return Diag(BaseLoc, diag::err_base_init_direct_and_virtual) - << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); + << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); // C++ [base.class.init]p2: // Unless the mem-initializer-id names a nonstatic data membeer of the // constructor's class ot a direst or virtual base of that class, the @@ -1410,7 +1428,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (!DirectBaseSpec && !VirtualBaseSpec) return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) << BaseType << Context.getTypeDeclType(ClassDecl) - << BaseTInfo->getTypeLoc().getSourceRange(); + << BaseTInfo->getTypeLoc().getLocalSourceRange(); CXXBaseSpecifier *BaseSpec = const_cast<CXXBaseSpecifier *>(DirectBaseSpec); @@ -1550,42 +1568,107 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ImplicitInitializerKind ImplicitInitKind, FieldDecl *Field, CXXBaseOrMemberInitializer *&CXXMemberInit) { + if (Field->isInvalidDecl()) + return true; + if (ImplicitInitKind == IIK_Copy) { - // FIXME: We should not return early here, but will do so until - // we know how to handle copy initialization of arrays. - CXXMemberInit = 0; - return false; - + SourceLocation Loc = Constructor->getLocation(); ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); Expr *MemberExprBase = DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, - SourceLocation(), ParamType, 0); + Loc, ParamType, 0); + + // Build a reference to this field within the parameter. + CXXScopeSpec SS; + LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc, + Sema::LookupMemberName); + MemberLookup.addDecl(Field, AS_public); + MemberLookup.resolveKind(); + Sema::OwningExprResult CopyCtorArg + = SemaRef.BuildMemberReferenceExpr(SemaRef.Owned(MemberExprBase), + ParamType, Loc, + /*IsArrow=*/false, + SS, + /*FirstQualifierInScope=*/0, + MemberLookup, + /*TemplateArgs=*/0); + if (CopyCtorArg.isInvalid()) + return true; + // When the field we are copying is an array, create index variables for + // each dimension of the array. We use these index variables to subscript + // the source array, and other clients (e.g., CodeGen) will perform the + // necessary iteration with these index variables. + llvm::SmallVector<VarDecl *, 4> IndexVariables; + QualType BaseType = Field->getType(); + QualType SizeType = SemaRef.Context.getSizeType(); + while (const ConstantArrayType *Array + = SemaRef.Context.getAsConstantArrayType(BaseType)) { + // Create the iteration variable for this array index. + IdentifierInfo *IterationVarName = 0; + { + llvm::SmallString<8> Str; + llvm::raw_svector_ostream OS(Str); + OS << "__i" << IndexVariables.size(); + IterationVarName = &SemaRef.Context.Idents.get(OS.str()); + } + VarDecl *IterationVar + = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, + IterationVarName, SizeType, + SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc), + VarDecl::None, VarDecl::None); + IndexVariables.push_back(IterationVar); + + // Create a reference to the iteration variable. + Sema::OwningExprResult IterationVarRef + = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, Loc); + assert(!IterationVarRef.isInvalid() && + "Reference to invented variable cannot fail!"); + + // Subscript the array with this iteration variable. + CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(move(CopyCtorArg), + Loc, + move(IterationVarRef), + Loc); + if (CopyCtorArg.isInvalid()) + return true; + + BaseType = Array->getElementType(); + } - Expr *CopyCtorArg = - MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false, - 0, SourceRange(), Field, - DeclAccessPair::make(Field, Field->getAccess()), - SourceLocation(), 0, - Field->getType().getNonReferenceType()); + // Construct the entity that we will be initializing. For an array, this + // will be first element in the array, which may require several levels + // of array-subscript entities. + llvm::SmallVector<InitializedEntity, 4> Entities; + Entities.reserve(1 + IndexVariables.size()); + Entities.push_back(InitializedEntity::InitializeMember(Field)); + for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) + Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context, + 0, + Entities.back())); - InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + // Direct-initialize to use the copy constructor. InitializationKind InitKind = - InitializationKind::CreateDirect(Constructor->getLocation(), - SourceLocation(), SourceLocation()); + InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, - &CopyCtorArg, 1); + Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>(); + InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, + &CopyCtorArgE, 1); - Sema::OwningExprResult MemberInit = - InitSeq.Perform(SemaRef, InitEntity, InitKind, - Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0); + Sema::OwningExprResult MemberInit + = InitSeq.Perform(SemaRef, Entities.back(), InitKind, + Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArgE, 1)); + MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit)); if (MemberInit.isInvalid()) return true; - - CXXMemberInit = 0; + + CXXMemberInit + = CXXBaseOrMemberInitializer::Create(SemaRef.Context, Field, Loc, Loc, + MemberInit.takeAs<Expr>(), Loc, + IndexVariables.data(), + IndexVariables.size()); return false; } @@ -1640,6 +1723,81 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, CXXMemberInit = 0; return false; } + +namespace { +struct BaseAndFieldInfo { + Sema &S; + CXXConstructorDecl *Ctor; + bool AnyErrorsInInits; + ImplicitInitializerKind IIK; + llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields; + llvm::SmallVector<CXXBaseOrMemberInitializer*, 8> AllToInit; + + BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits) + : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) { + // FIXME: Handle implicit move constructors. + if (Ctor->isImplicit() && Ctor->isCopyConstructor()) + IIK = IIK_Copy; + else + IIK = IIK_Default; + } +}; +} + +static bool CollectFieldInitializer(BaseAndFieldInfo &Info, + FieldDecl *Top, FieldDecl *Field) { + + // Overwhelmingly common case: we have a direct initializer for this field. + if (CXXBaseOrMemberInitializer *Init = Info.AllBaseFields.lookup(Field)) { + Info.AllToInit.push_back(Init); + + if (Field != Top) { + Init->setMember(Top); + Init->setAnonUnionMember(Field); + } + return false; + } + + if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) { + const RecordType *FieldClassType = Field->getType()->getAs<RecordType>(); + assert(FieldClassType && "anonymous struct/union without record type"); + + // Walk through the members, tying in any initializers for fields + // we find. The earlier semantic checks should prevent redundant + // initialization of union members, given the requirement that + // union members never have non-trivial default constructors. + + // TODO: in C++0x, it might be legal to have union members with + // non-trivial default constructors in unions. Revise this + // implementation then with the appropriate semantics. + CXXRecordDecl *FieldClassDecl + = cast<CXXRecordDecl>(FieldClassType->getDecl()); + for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), + EA = FieldClassDecl->field_end(); FA != EA; FA++) + if (CollectFieldInitializer(Info, Top, *FA)) + return true; + } + + // Don't try to build an implicit initializer if there were semantic + // errors in any of the initializers (and therefore we might be + // missing some that the user actually wrote). + if (Info.AnyErrorsInInits) + return false; + + CXXBaseOrMemberInitializer *Init = 0; + if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Init)) + return true; + + // If the member doesn't need to be initialized, Init will still be null. + if (!Init) return false; + + Info.AllToInit.push_back(Init); + if (Top != Field) { + Init->setMember(Top); + Init->setAnonUnionMember(Field); + } + return false; +} bool Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, @@ -1661,11 +1819,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, return false; } - ImplicitInitializerKind ImplicitInitKind = IIK_Default; - - // FIXME: Handle implicit move constructors. - if (Constructor->isImplicit() && Constructor->isCopyConstructor()) - ImplicitInitKind = IIK_Copy; + BaseAndFieldInfo Info(*this, Constructor, AnyErrors); // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. @@ -1673,17 +1827,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, if (!ClassDecl) return true; - llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; - llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields; bool HadError = false; for (unsigned i = 0; i < NumInitializers; i++) { CXXBaseOrMemberInitializer *Member = Initializers[i]; if (Member->isBaseInitializer()) - AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member; + Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member; else - AllBaseFields[Member->getMember()] = Member; + Info.AllBaseFields[Member->getMember()] = Member; } // Keep track of the direct virtual bases. @@ -1699,22 +1851,23 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, E = ClassDecl->vbases_end(); VBase != E; ++VBase) { if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { - AllToInit.push_back(Value); + = Info.AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { + Info.AllToInit.push_back(Value); } else if (!AnyErrors) { bool IsInheritedVirtualBase = !DirectVBases.count(VBase); CXXBaseOrMemberInitializer *CXXBaseInit; - if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, VBase, IsInheritedVirtualBase, CXXBaseInit)) { HadError = true; continue; } - AllToInit.push_back(CXXBaseInit); + Info.AllToInit.push_back(CXXBaseInit); } } + // Non-virtual bases. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { // Virtuals are in the virtual base list and already constructed. @@ -1722,70 +1875,39 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { - AllToInit.push_back(Value); + = Info.AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { + Info.AllToInit.push_back(Value); } else if (!AnyErrors) { CXXBaseOrMemberInitializer *CXXBaseInit; - if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, Base, /*IsInheritedVirtualBase=*/false, CXXBaseInit)) { HadError = true; continue; } - AllToInit.push_back(CXXBaseInit); + Info.AllToInit.push_back(CXXBaseInit); } } - // non-static data members. + // Fields. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) { - if ((*Field)->isAnonymousStructOrUnion()) { - if (const RecordType *FieldClassType = - Field->getType()->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), - EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) { - // 'Member' is the anonymous union field and 'AnonUnionMember' is - // set to the anonymous union data member used in the initializer - // list. - Value->setMember(*Field); - Value->setAnonUnionMember(*FA); - AllToInit.push_back(Value); - break; - } - } - } - continue; - } - if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) { - AllToInit.push_back(Value); + if ((*Field)->getType()->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); continue; } - - if (AnyErrors) - continue; - - CXXBaseOrMemberInitializer *Member; - if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind, - *Field, Member)) { + if (CollectFieldInitializer(Info, *Field, *Field)) HadError = true; - continue; - } - - // If the member doesn't need to be initialized, it will be null. - if (Member) - AllToInit.push_back(Member); } - NumInitializers = AllToInit.size(); + NumInitializers = Info.AllToInit.size(); if (NumInitializers > 0) { Constructor->setNumBaseOrMemberInitializers(NumInitializers); CXXBaseOrMemberInitializer **baseOrMemberInitializers = new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; - memcpy(baseOrMemberInitializers, AllToInit.data(), + memcpy(baseOrMemberInitializers, Info.AllToInit.data(), NumInitializers * sizeof(CXXBaseOrMemberInitializer*)); Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); @@ -1900,9 +2022,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, // If we didn't find this initializer, it must be because we // scanned past it on a previous iteration. That can only // happen if we're out of order; emit a warning. - if (IdealIndex == NumIdealInits) { - assert(PrevInit && "initializer not found in initializer list"); - + if (IdealIndex == NumIdealInits && PrevInit) { Sema::SemaDiagnosticBuilder D = SemaRef.Diag(PrevInit->getSourceLocation(), diag::warn_initializer_out_of_order); @@ -2028,6 +2148,9 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, for (unsigned i = 0; i < NumMemInits; i++) { CXXBaseOrMemberInitializer *Init = MemInits[i]; + // Set the source order index. + Init->setSourceOrder(i); + if (Init->isMemberInitializer()) { FieldDecl *Field = Init->getMember(); if (CheckRedundantInit(*this, Init, Members[Field]) || @@ -2064,7 +2187,8 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { FieldDecl *Field = *I; - + if (Field->isInvalidDecl()) + continue; QualType FieldType = Context.getBaseElementType(Field->getType()); const RecordType* RT = FieldType->getAs<RecordType>(); @@ -2403,6 +2527,9 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { } } } + + if (Record->isDynamicClass()) + DynamicClasses.push_back(Record); } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, @@ -2530,7 +2657,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, Context.getFunctionType(Context.VoidTy, &ArgType, 1, false, 0, - /*FIXME:*/false, + /*FIXME: hasExceptionSpec*/false, false, 0, 0, FunctionType::ExtInfo()), /*TInfo=*/0, @@ -2623,7 +2750,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(RetType, &ArgType, 1, false, 0, - /*FIXME:*/false, + /*FIXME: hasExceptionSpec*/false, false, 0, 0, FunctionType::ExtInfo()), /*TInfo=*/0, /*isStatic=*/false, @@ -2659,7 +2786,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, // inline public member of its class. QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, - /*FIXME:*/false, + /*FIXME: hasExceptionSpec*/false, false, 0, 0, FunctionType::ExtInfo()); DeclarationName Name @@ -3817,8 +3944,9 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // A using-declaration is a declaration and can therefore be used // repeatedly where (and only where) multiple declarations are // allowed. - // That's only in file contexts. - if (CurContext->getLookupContext()->isFileContext()) + // + // That's in non-member contexts. + if (!CurContext->getLookupContext()->isRecord()) return false; NestedNameSpecifier *Qual @@ -4082,12 +4210,15 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); ImplicitlyDefinedFunctionScope Scope(*this, Constructor); - if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) { + ErrorTrap Trap(*this); + if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false) || + Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); } else { Constructor->setUsed(); + MarkVTableUsed(CurrentLocation, ClassDecl); } } @@ -4098,14 +4229,16 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); + if (Destructor->isInvalidDecl()) + return; + ImplicitlyDefinedFunctionScope Scope(*this, Destructor); + ErrorTrap Trap(*this); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); - // FIXME: If CheckDestructor fails, we should emit a note about where the - // implicit destructor was needed. - if (CheckDestructor(Destructor)) { + if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXDestructor << Context.getTagDeclType(ClassDecl); @@ -4114,6 +4247,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, } Destructor->setUsed(); + MarkVTableUsed(CurrentLocation, ClassDecl); } /// \brief Builds a statement that copies the given entity from \p From to @@ -4332,6 +4466,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CopyAssignOperator->setUsed(); ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator); + ErrorTrap Trap(*this); // C++0x [class.copy]p30: // The implicitly-defined or explicitly-defaulted copy assignment operator @@ -4407,8 +4542,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, move(To), Owned(From), /*CopyingBaseSubobject=*/true); if (Copy.isInvalid()) { - Invalid = true; - continue; + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); + CopyAssignOperator->setInvalidDecl(); + return; } // Success! Record the copy. @@ -4427,7 +4564,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(Loc, diag::note_first_required_here); + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -4438,12 +4576,18 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(Loc, diag::note_first_required_here); + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } QualType FieldType = Field->getType().getNonReferenceType(); + if (FieldType->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); + continue; + } // Build references to the field in the object we're copying from and to. CXXScopeSpec SS; // Intentionally empty @@ -4528,8 +4672,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, move(To), move(From), /*CopyingBaseSubobject=*/false); if (Copy.isInvalid()) { - Invalid = true; - continue; + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); + CopyAssignOperator->setInvalidDecl(); + return; } // Success! Record the copy. @@ -4546,6 +4692,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Invalid = true; else { Statements.push_back(Return.takeAs<Stmt>()); + + if (Trap.hasErrorOccurred()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); + Invalid = true; + } } } @@ -4572,37 +4724,22 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor); + ErrorTrap Trap(*this); - if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) { + if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) || + Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); + << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); CopyConstructor->setInvalidDecl(); - } else { - CopyConstructor->setUsed(); - } - - // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of - // fields, this code below should be removed. - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++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 (CXXConstructorDecl *FieldCopyCtor = - FieldClassDecl->getCopyConstructor(Context, TypeQuals)) { - CheckDirectMemberAccess(Field->getLocation(), - FieldCopyCtor, - PDiag(diag::err_access_copy_field) - << Field->getDeclName() << Field->getType()); - - MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor); - } - } + } else { + CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(), + CopyConstructor->getLocation(), + MultiStmtArg(*this, 0, 0), + /*isStmtExpr=*/false) + .takeAs<Stmt>()); } + + CopyConstructor->setUsed(); } Sema::OwningExprResult @@ -4672,7 +4809,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD, void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl()); if (!ClassDecl->isInvalidDecl() && !VD->isInvalidDecl() && - !ClassDecl->hasTrivialDestructor()) { + !ClassDecl->hasTrivialDestructor() && !ClassDecl->isDependentContext()) { CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context); MarkDeclarationReferenced(VD->getLocation(), Destructor); CheckDestructorAccess(VD->getLocation(), Destructor, @@ -5419,7 +5556,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); QualType T = TSInfo->getType(); - SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange(); + SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange(); if (!getLangOptions().CPlusPlus0x) { // C++03 [class.friend]p2: @@ -5948,90 +6085,125 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return Dcl; } -static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) { - // Ignore dependent types. - if (MD->isDependentContext()) - return false; - - // Ignore declarations that are not definitions. - if (!MD->isThisDeclarationADefinition()) - return false; - - CXXRecordDecl *RD = MD->getParent(); - - // Ignore classes without a vtable. - if (!RD->isDynamicClass()) - return false; - - switch (MD->getParent()->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - // Classes that aren't instantiations of templates don't need their - // virtual methods marked until we see the definition of the key - // function. - break; +void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, + bool DefinitionRequired) { + // Ignore any vtable uses in unevaluated operands or for classes that do + // not have a vtable. + if (!Class->isDynamicClass() || Class->isDependentContext() || + CurContext->isDependentContext() || + ExprEvalContexts.back().Context == Unevaluated) + return; - case TSK_ImplicitInstantiation: - // This is a constructor of a class template; mark all of the virtual - // members as referenced to ensure that they get instantiatied. - if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) - return true; - break; + // Try to insert this class into the map. + Class = cast<CXXRecordDecl>(Class->getCanonicalDecl()); + std::pair<llvm::DenseMap<CXXRecordDecl *, bool>::iterator, bool> + Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired)); + if (!Pos.second) { + // If we already had an entry, check to see if we are promoting this vtable + // to required a definition. If so, we need to reappend to the VTableUses + // list, since we may have already processed the first entry. + if (DefinitionRequired && !Pos.first->second) { + Pos.first->second = true; + } else { + // Otherwise, we can early exit. + return; + } + } - case TSK_ExplicitInstantiationDeclaration: - return false; + // Local classes need to have their virtual members marked + // immediately. For all other classes, we mark their virtual members + // at the end of the translation unit. + if (Class->isLocalClass()) + MarkVirtualMembersReferenced(Loc, Class); + else + VTableUses.push_back(std::make_pair(Class, Loc)); +} - case TSK_ExplicitInstantiationDefinition: - // This is method of a explicit instantiation; mark all of the virtual - // members as referenced to ensure that they get instantiatied. - return true; +bool Sema::DefineUsedVTables() { + // If any dynamic classes have their key function defined within + // this translation unit, then those vtables are considered "used" and must + // be emitted. + for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { + if (const CXXMethodDecl *KeyFunction + = Context.getKeyFunction(DynamicClasses[I])) { + const FunctionDecl *Definition = 0; + if (KeyFunction->getBody(Definition)) + MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true); + } } - // Consider only out-of-line definitions of member functions. When we see - // an inline definition, it's too early to compute the key function. - if (!MD->isOutOfLine()) + if (VTableUses.empty()) return false; + + // Note: The VTableUses vector could grow as a result of marking + // the members of a class as "used", so we check the size each + // time through the loop and prefer indices (with are stable) to + // iterators (which are not). + for (unsigned I = 0; I != VTableUses.size(); ++I) { + CXXRecordDecl *Class = VTableUses[I].first->getDefinition(); + if (!Class) + continue; - const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); - - // If there is no key function, we will need a copy of the vtable. - if (!KeyFunction) - return true; - - // If this is the key function, we need to mark virtual members. - if (KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl()) - return true; - - return false; -} - -void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, - CXXMethodDecl *MD) { - CXXRecordDecl *RD = MD->getParent(); + SourceLocation Loc = VTableUses[I].second; + + // If this class has a key function, but that key function is + // defined in another translation unit, we don't need to emit the + // vtable even though we're using it. + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(Class); + if (KeyFunction && !KeyFunction->getBody()) { + switch (KeyFunction->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDeclaration: + // The key function is in another translation unit. + continue; - // We will need to mark all of the virtual members as referenced to build the - // vtable. - if (!needsVTable(MD, Context)) - return; + case TSK_ExplicitInstantiationDefinition: + case TSK_ImplicitInstantiation: + // We will be instantiating the key function. + break; + } + } else if (!KeyFunction) { + // If we have a class with no key function that is the subject + // of an explicit instantiation declaration, suppress the + // vtable; it will live with the explicit instantiation + // definition. + bool IsExplicitInstantiationDeclaration + = Class->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration; + for (TagDecl::redecl_iterator R = Class->redecls_begin(), + REnd = Class->redecls_end(); + R != REnd; ++R) { + TemplateSpecializationKind TSK + = cast<CXXRecordDecl>(*R)->getTemplateSpecializationKind(); + if (TSK == TSK_ExplicitInstantiationDeclaration) + IsExplicitInstantiationDeclaration = true; + else if (TSK == TSK_ExplicitInstantiationDefinition) { + IsExplicitInstantiationDeclaration = false; + break; + } + } - TemplateSpecializationKind kind = RD->getTemplateSpecializationKind(); - if (kind == TSK_ImplicitInstantiation) - ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc)); - else - MarkVirtualMembersReferenced(Loc, RD); -} + if (IsExplicitInstantiationDeclaration) + continue; + } -bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() { - if (ClassesWithUnmarkedVirtualMembers.empty()) - return false; - - while (!ClassesWithUnmarkedVirtualMembers.empty()) { - CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first; - SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second; - ClassesWithUnmarkedVirtualMembers.pop_back(); - MarkVirtualMembersReferenced(Loc, RD); + // Mark all of the virtual members of this class as referenced, so + // that we can build a vtable. Then, tell the AST consumer that a + // vtable for this class is required. + MarkVirtualMembersReferenced(Loc, Class); + CXXRecordDecl *Canonical = cast<CXXRecordDecl>(Class->getCanonicalDecl()); + Consumer.HandleVTable(Class, VTablesUsed[Canonical]); + + // Optionally warn if we're emitting a weak vtable. + if (Class->getLinkage() == ExternalLinkage && + Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { + if (!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined())) + Diag(Class->getLocation(), diag::warn_weak_vtable) << Class; + } } - + VTableUses.clear(); + return true; } @@ -6076,6 +6248,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; for (unsigned i = 0; i < ivars.size(); i++) { FieldDecl *Field = ivars[i]; + if (Field->isInvalidDecl()) + continue; + CXXBaseOrMemberInitializer *Member; InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); InitializationKind InitKind = @@ -6098,6 +6273,20 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { MemberInit.takeAs<Expr>(), SourceLocation()); AllToInit.push_back(Member); + + // Be sure that the destructor is accessible and is marked as referenced. + if (const RecordType *RecordTy + = Context.getBaseElementType(Field->getType()) + ->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (CXXDestructorDecl *Destructor + = const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) { + MarkDeclarationReferenced(Field->getLocation(), Destructor); + CheckDestructorAccess(Field->getLocation(), Destructor, + PDiag(diag::err_access_dtor_ivar) + << Context.getBaseElementType(Field->getType())); + } + } } ObjCImplementation->setIvarInitializers(Context, AllToInit.data(), AllToInit.size()); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index d446cc13da26..3b05f5ac28da 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -142,8 +142,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // typedef. If we do, get the underlying class type. if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) { QualType T = TDecl->getUnderlyingType(); - if (T->isObjCInterfaceType()) { - if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) + if (T->isObjCObjectType()) { + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); } } @@ -210,8 +210,8 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, LookupOrdinaryName, ForRedeclaration); if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) { QualType T = TDecl->getUnderlyingType(); - if (T->isObjCInterfaceType()) { - if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) { + if (T->isObjCObjectType()) { + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { ClassName = IDecl->getIdentifier(); CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, LookupOrdinaryName, ForRedeclaration); @@ -763,6 +763,10 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, << (*IM)->getType(); Diag((*IF)->getLocation(), diag::note_previous_definition); } + if (ImpMethodDecl->isVariadic() != IntfMethodDecl->isVariadic()) { + Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic); + Diag(IntfMethodDecl->getLocation(), diag::note_previous_declaration); + } } /// FIXME: Type hierarchies in Objective-C can be deep. We could most likely @@ -925,7 +929,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, } } -void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, +void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { llvm::DenseSet<Selector> InsMap; @@ -938,8 +942,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, // Check and see if properties declared in the interface have either 1) // an implementation or 2) there is a @synthesize/@dynamic implementation // of the property in the @implementation. - if (isa<ObjCInterfaceDecl>(CDecl)) - DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + if (isa<ObjCInterfaceDecl>(CDecl) && !LangOpts.ObjCNonFragileABI2) + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); llvm::DenseSet<Selector> ClsMap; for (ObjCImplementationDecl::classmeth_iterator @@ -968,7 +972,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, for (ObjCCategoryDecl *Categories = I->getCategoryList(); Categories; Categories = Categories->getNextClassCategory()) { if (Categories->IsClassExtension()) { - ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl); + ImplMethodsVsClassMethods(S, IMPDecl, Categories, IncompleteImpl); break; } } @@ -990,7 +994,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) InsMap.insert((*I)->getSelector()); } - DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); } } else assert(false && "invalid ObjCContainerDecl type."); @@ -1024,15 +1028,15 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, // // FIXME: Make an extension? TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl); - if (!TDD || !isa<ObjCInterfaceType>(TDD->getUnderlyingType())) { + if (!TDD || !TDD->getUnderlyingType()->isObjCObjectType()) { Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i]; Diag(PrevDecl->getLocation(), diag::note_previous_definition); - } else if (TDD) { + } else { // a forward class declaration matching a typedef name of a class refers // to the underlying class. - if (ObjCInterfaceType * OI = - dyn_cast<ObjCInterfaceType>(TDD->getUnderlyingType())) - PrevDecl = OI->getDecl(); + if (const ObjCObjectType *OI = + TDD->getUnderlyingType()->getAs<ObjCObjectType>()) + PrevDecl = OI->getInterface(); } } ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); @@ -1326,7 +1330,7 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, // Note: For class/category implemenations, allMethods/allProperties is // always null. -void Sema::ActOnAtEnd(SourceRange AtEnd, +void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, DeclPtrTy classDecl, DeclPtrTy *allMethods, unsigned allNum, DeclPtrTy *allProperties, unsigned pNum, @@ -1433,7 +1437,9 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { IC->setAtEndRange(AtEnd); if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) { - ImplMethodsVsClassMethods(IC, IDecl); + if (LangOpts.ObjCNonFragileABI2) + DefaultSynthesizeProperties(S, IC, IDecl); + ImplMethodsVsClassMethods(S, IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); if (LangOpts.ObjCNonFragileABI2) while (IDecl->getSuperClass()) { @@ -1452,7 +1458,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, for (ObjCCategoryDecl *Categories = IDecl->getCategoryList(); Categories; Categories = Categories->getNextClassCategory()) { if (Categories->getIdentifier() == CatImplClass->getIdentifier()) { - ImplMethodsVsClassMethods(CatImplClass, Categories); + ImplMethodsVsClassMethods(S, CatImplClass, Categories); break; } } @@ -1530,7 +1536,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( // Methods cannot return interface types. All ObjC objects are // passed by reference. - if (resultDeclType->isObjCInterfaceType()) { + if (resultDeclType->isObjCObjectType()) { Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value) << 0 << resultDeclType; return DeclPtrTy(); @@ -1568,7 +1574,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( ArgInfo[i].Name, ArgType, DI, VarDecl::None, VarDecl::None, 0); - if (ArgType->isObjCInterfaceType()) { + if (ArgType->isObjCObjectType()) { Diag(ArgInfo[i].NameLoc, diag::err_object_cannot_be_passed_returned_by_value) << 1 << ArgType; @@ -1592,7 +1598,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( else // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). ArgType = adjustParameterType(ArgType); - if (ArgType->isObjCInterfaceType()) { + if (ArgType->isObjCObjectType()) { Diag(Param->getLocation(), diag::err_object_cannot_be_passed_returned_by_value) << 1 << ArgType; @@ -1810,7 +1816,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, E = OI->ivar_end(); I != E; ++I) { ObjCIvarDecl *Iv = (*I); QualType QT = Context.getBaseElementType(Iv->getType()); - if (isa<RecordType>(QT)) + if (QT->isRecordType()) Ivars.push_back(*I); } @@ -1820,7 +1826,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, E = CDecl->ivar_end(); I != E; ++I) { ObjCIvarDecl *Iv = (*I); QualType QT = Context.getBaseElementType(Iv->getType()); - if (isa<RecordType>(QT)) + if (QT->isRecordType()) Ivars.push_back(*I); } } @@ -1832,7 +1838,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, E = ImplDecl->ivar_end(); I != E; ++I) { ObjCIvarDecl *Iv = (*I); QualType QT = Context.getBaseElementType(Iv->getType()); - if (isa<RecordType>(QT)) + if (QT->isRecordType()) Ivars.push_back(*I); } } diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 53e9385749fb..7d73fe4777bd 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -389,7 +389,7 @@ bool Sema::CheckExceptionSpecSubset( if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths)) continue; - if (Paths.isAmbiguous(CanonicalSuperT)) + if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT))) continue; // Do this check from a context without privileges. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 869d6df2f094..f745352d998f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -22,6 +22,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -160,16 +161,19 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ++sentinel; } Expr *sentinelExpr = Args[sentinel]; - if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) && - !sentinelExpr->isTypeDependent() && - !sentinelExpr->isValueDependent() && - (!sentinelExpr->getType()->isPointerType() || - !sentinelExpr->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)))) { - Diag(Loc, diag::warn_missing_sentinel) << isMethod; - Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; - } - return; + if (!sentinelExpr) return; + if (sentinelExpr->isTypeDependent()) return; + if (sentinelExpr->isValueDependent()) return; + if (sentinelExpr->getType()->isPointerType() && + sentinelExpr->IgnoreParenCasts()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) + return; + + // Unfortunately, __null has type 'int'. + if (isa<GNUNullExpr>(sentinelExpr)) return; + + Diag(Loc, diag::warn_missing_sentinel) << isMethod; + Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; } SourceRange Sema::getExprRange(ExprTy *E) const { @@ -275,10 +279,9 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); // If this is a 'float' (CVR qualified or typedef) promote to double. - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) - if (BT->getKind() == BuiltinType::Float) - return ImpCastExprToType(Expr, Context.DoubleTy, - CastExpr::CK_FloatingCast); + if (Ty->isSpecificBuiltinType(BuiltinType::Float)) + return ImpCastExprToType(Expr, Context.DoubleTy, + CastExpr::CK_FloatingCast); UsualUnaryConversions(Expr); } @@ -287,10 +290,17 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { /// will warn if the resulting type is not a POD type, and rejects ObjC /// interfaces passed by value. This returns true if the argument type is /// completely illegal. -bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { +bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, + FunctionDecl *FDecl) { DefaultArgumentPromotion(Expr); - if (Expr->getType()->isObjCInterfaceType() && + // __builtin_va_start takes the second argument as a "varargs" argument, but + // it doesn't actually do anything with it. It doesn't need to be non-pod + // etc. + if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start) + return false; + + if (Expr->getType()->isObjCObjectType() && DiagRuntimeBehavior(Expr->getLocStart(), PDiag(diag::err_cannot_pass_objc_interface_to_vararg) << Expr->getType() << CT)) @@ -486,35 +496,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, D, Loc, Ty)); } -/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or -/// variable corresponding to the anonymous union or struct whose type -/// is Record. -static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context, - RecordDecl *Record) { - assert(Record->isAnonymousStructOrUnion() && - "Record must be an anonymous struct or union!"); - - // FIXME: Once Decls are directly linked together, this will be an O(1) - // operation rather than a slow walk through DeclContext's vector (which - // itself will be eliminated). DeclGroups might make this even better. - DeclContext *Ctx = Record->getDeclContext(); - for (DeclContext::decl_iterator D = Ctx->decls_begin(), - DEnd = Ctx->decls_end(); - D != DEnd; ++D) { - if (*D == Record) { - // The object for the anonymous struct/union directly - // follows its type in the list of declarations. - ++D; - assert(D != DEnd && "Missing object for anonymous record"); - assert(!cast<NamedDecl>(*D)->getDeclName() && "Decl should be unnamed"); - return *D; - } - } - - assert(false && "Missing object for anonymous record"); - return 0; -} - /// \brief Given a field that represents a member of an anonymous /// struct/union, build the path from that field's context to the /// actual member. @@ -539,7 +520,7 @@ VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field, DeclContext *Ctx = Field->getDeclContext(); do { RecordDecl *Record = cast<RecordDecl>(Ctx); - Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record); + ValueDecl *AnonObject = Record->getAnonymousStructOrUnionObject(); if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject)) Path.push_back(AnonField); else { @@ -592,7 +573,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, // We've found a member of an anonymous struct/union that is // inside a non-anonymous struct/union, so in a well-formed // program our base object expression is "this". - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { + DeclContext *DC = getFunctionLevelDeclContext(); + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) { if (!MD->isStatic()) { QualType AnonFieldType = Context.getTagDeclType( @@ -828,9 +810,10 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, const LookupResult &R) { assert(!R.empty() && (*R.begin())->isCXXClassMember()); + DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); bool isStaticContext = - (!isa<CXXMethodDecl>(SemaRef.CurContext) || - cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic()); + (!isa<CXXMethodDecl>(DC) || + cast<CXXMethodDecl>(DC)->isStatic()); if (R.isUnresolvableResult()) return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; @@ -870,7 +853,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, // declaring classes, it can't be an implicit member reference (in // which case it's an error if any of those members are selected). if (IsProvablyNotDerivedFrom(SemaRef, - cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(), + cast<CXXMethodDecl>(DC)->getParent(), Classes)) return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); @@ -907,7 +890,7 @@ static void DiagnoseInstanceReference(Sema &SemaRef, /// /// \return false if new lookup candidates were found bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, - LookupResult &R) { + LookupResult &R, CorrectTypoContext CTC) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; @@ -958,7 +941,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, // We didn't find anything, so try to correct for a typo. DeclarationName Corrected; - if (S && (Corrected = CorrectTypo(R, S, &SS))) { + if (S && (Corrected = CorrectTypo(R, S, &SS, false, CTC))) { if (!R.empty()) { if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) { if (SS.isEmpty()) @@ -1067,17 +1050,14 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // Perform the required lookup. LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); if (TemplateArgs) { - // Just re-use the lookup done by isTemplateName. - DecomposeTemplateName(R, Id); - - // Re-derive the naming class. - if (SS.isSet()) { - NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - if (const Type *Ty = Qualifier->getAsType()) - if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl()) - R.setNamingClass(NamingClass); - } + // Lookup the template name again to correctly establish the context in + // which it was found. This is really unfortunate as we already did the + // lookup to determine that it was a template name in the first place. If + // this becomes a performance hit, we can work harder to preserve those + // results until we get here but it's likely not worth it. + bool MemberOfUnknownSpecialization; + LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, + MemberOfUnknownSpecialization); } else { bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); @@ -1112,7 +1092,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. if (R.empty()) { - if (DiagnoseEmptyLookup(S, SS, R)) + if (DiagnoseEmptyLookup(S, SS, R, CTC_Unknown)) return ExprError(); assert(!R.empty() && @@ -1166,7 +1146,8 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, QualType T = Func->getType(); QualType NoProtoType = T; if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>()) - NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType()); + NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType(), + Proto->getExtInfo()); return BuildDeclRefExpr(Func, NoProtoType, NameLoc, &SS); } } @@ -1423,6 +1404,9 @@ Sema::PerformObjectMemberConversion(Expr *&From, SourceRange FromRange = From->getSourceRange(); SourceLocation FromLoc = FromRange.getBegin(); + bool isLvalue + = (From->isLvalue(Context) == Expr::LV_Valid) && !PointerConversions; + // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its // class name. @@ -1460,7 +1444,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (PointerConversions) QType = Context.getPointerType(QType); ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/!PointerConversions, BasePath); + isLvalue, BasePath); FromType = QType; FromRecordType = QRecordType; @@ -1497,7 +1481,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (PointerConversions) UType = Context.getPointerType(UType); ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/!PointerConversions, BasePath); + isLvalue, BasePath); FromType = UType; FromRecordType = URecordType; } @@ -1514,7 +1498,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, return true; ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/!PointerConversions, BasePath); + isLvalue, BasePath); return false; } @@ -1558,7 +1542,8 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, // If this is known to be an instance access, go ahead and build a // 'this' expression now. - QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); + DeclContext *DC = getFunctionLevelDeclContext(); + QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); Expr *This = 0; // null signifies implicit access if (IsKnownInstance) { SourceLocation Loc = R.getNameLoc(); @@ -1682,8 +1667,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, (NestedNameSpecifier*) SS.getScopeRep(), SS.getRange(), R.getLookupName(), R.getNameLoc(), - NeedsADL, R.isOverloadedResult()); - ULE->addDecls(R.begin(), R.end()); + NeedsADL, R.isOverloadedResult(), + R.begin(), R.end()); return Owned(ULE); } @@ -2036,12 +2021,18 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, return true; // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. - if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) { + if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) { Diag(OpLoc, diag::err_sizeof_nonfragile_interface) << exprType << isSizeof << ExprRange; return true; } + if (Context.hasSameUnqualifiedType(exprType, Context.OverloadTy)) { + Diag(OpLoc, diag::err_sizeof_alignof_overloaded_function_type) + << !isSizeof << ExprRange; + return true; + } + return false; } @@ -2312,7 +2303,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, return ExprError(); // Diagnose bad cases where we step over interface counts. - if (ResultType->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + if (ResultType->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(LLoc, diag::err_subscript_nonfragile_interface) << ResultType << BaseExpr->getSourceRange(); return ExprError(); @@ -2665,6 +2656,9 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, if (Result.get()) return move(Result); + + // LookupMemberExpr can modify Base, and thus change BaseType + BaseType = Base->getType(); } return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType, @@ -2741,8 +2735,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, IsArrow, OpLoc, Qualifier, SS.getRange(), MemberName, MemberLoc, - TemplateArgs); - MemExpr->addDecls(R.begin(), R.end()); + TemplateArgs, R.begin(), R.end()); return Owned(MemExpr); } @@ -2917,7 +2910,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Handle the following exceptional case PObj->isa. if (const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>()) { - if (OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && + if (OPT->getObjectType()->isObjCId() && MemberName.getAsIdentifierInfo()->isStr("isa")) return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc, Context.getObjCClassType())); @@ -3041,8 +3034,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, } } - // Handle field access to simple records. This also handles access - // to fields of the ObjC 'id' struct. + // Handle field access to simple records. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(), RTy, OpLoc, SS)) @@ -3053,14 +3045,14 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Handle access to Objective-C instance variables, such as "Obj->ivar" and // (*Obj).ivar. if ((IsArrow && BaseType->isObjCObjectPointerType()) || - (!IsArrow && BaseType->isObjCInterfaceType())) { + (!IsArrow && BaseType->isObjCObjectType())) { const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>(); - const ObjCInterfaceType *IFaceT = - OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>(); - if (IFaceT) { + ObjCInterfaceDecl *IDecl = + OPT ? OPT->getInterfaceDecl() + : BaseType->getAs<ObjCObjectType>()->getInterface(); + if (IDecl) { IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - ObjCInterfaceDecl *IDecl = IFaceT->getDecl(); ObjCInterfaceDecl *ClassDeclared; ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); @@ -3173,7 +3165,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Handle the following exceptional case (*Obj).isa. if (!IsArrow && - BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) && + BaseType->isObjCObjectType() && + BaseType->getAs<ObjCObjectType>()->isObjCId() && MemberName.getAsIdentifierInfo()->isStr("isa")) return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc, Context.getObjCClassType())); @@ -3471,9 +3464,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, // If this is a variadic call, handle args passed through "...". if (CallType != VariadicDoesNotApply) { // Promote the arguments (C99 6.5.2.2p7). - for (unsigned i = ArgIx; i < NumArgs; i++) { + for (unsigned i = ArgIx; i != NumArgs; ++i) { Expr *Arg = Args[i]; - Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType); + Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType, FDecl); AllArgs.push_back(Arg); } } @@ -4081,8 +4074,6 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (getLangOptions().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc); - CheckSignCompare(LHS, RHS, QuestionLoc); - UsualUnaryConversions(Cond); UsualUnaryConversions(LHS); UsualUnaryConversions(RHS); @@ -4659,7 +4650,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return Incompatible; } - if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) + if (lhsType->isArithmeticType() && rhsType->isArithmeticType() && + !(getLangOptions().CPlusPlus && lhsType->isEnumeralType())) return Compatible; if (isa<PointerType>(lhsType)) { @@ -4917,7 +4909,13 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { if (const VectorType *RV = rhsType->getAs<VectorType>()) if (LV->getElementType() == RV->getElementType() && LV->getNumElements() == RV->getNumElements()) { - return lhsType->isExtVectorType() ? lhsType : rhsType; + if (lhsType->isExtVectorType()) { + ImpCastExprToType(rex, lhsType, CastExpr::CK_BitCast); + return lhsType; + } + + ImpCastExprToType(lex, rhsType, CastExpr::CK_BitCast); + return rhsType; } } } @@ -5059,7 +5057,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 return QualType(); } // Diagnose bad cases where we step over interface counts. - if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) << PointeeTy << PExp->getSourceRange(); return QualType(); @@ -5135,7 +5133,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, return QualType(); // Diagnose bad cases where we step over interface counts. - if (lpointee->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) << lpointee << lex->getSourceRange(); return QualType(); @@ -5274,8 +5272,6 @@ 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, &Opc); - // C99 6.5.8p3 / C99 6.5.9p4 if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) UsualArithmeticConversions(lex, rex); @@ -5904,7 +5900,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, << ResType)) return QualType(); // Diagnose bad cases where we step over interface counts. - else if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + else if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) << PointeeTy << Op->getSourceRange(); return QualType(); @@ -6626,7 +6622,7 @@ Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, SourceLocation RParenLoc) { QualType ArgTy = TInfo->getType(); bool Dependent = ArgTy->isDependentType(); - SourceRange TypeRange = TInfo->getTypeLoc().getSourceRange(); + SourceRange TypeRange = TInfo->getTypeLoc().getLocalSourceRange(); // We must have at least one component that refers to the type, and the first // one is known to be a field designator. Verify that the ArgTy represents @@ -7018,7 +7014,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType(); // Do not allow returning a objc interface by-value. - if (RetTy->isObjCInterfaceType()) { + if (RetTy->isObjCObjectType()) { Diag(ParamInfo.getSourceRange().getBegin(), diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; return; @@ -7090,7 +7086,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { QualType RetTy = T->getAs<FunctionType>()->getResultType(); // Do not allow returning a objc interface by-value. - if (RetTy->isObjCInterfaceType()) { + if (RetTy->isObjCObjectType()) { Diag(ParamInfo.getSourceRange().getBegin(), diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; } else if (!RetTy->isDependentType()) @@ -7500,22 +7496,24 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); } - MaybeMarkVirtualMembersReferenced(Loc, Constructor); + MarkVTableUsed(Loc, Constructor->getParent()); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { if (Destructor->isImplicit() && !Destructor->isUsed()) DefineImplicitDestructor(Loc, Destructor); - + if (Destructor->isVirtual()) + MarkVTableUsed(Loc, Destructor->getParent()); } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) { if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { if (!MethodDecl->isUsed()) DefineImplicitCopyAssignment(Loc, MethodDecl); - } + } else if (MethodDecl->isVirtual()) + MarkVTableUsed(Loc, MethodDecl->getParent()); } if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { // Implicit instantiation of function templates and member functions of // class templates. - if (!Function->getBody() && Function->isImplicitlyInstantiable()) { + if (Function->isImplicitlyInstantiable()) { bool AlreadyInstantiated = false; if (FunctionTemplateSpecializationInfo *SpecInfo = Function->getTemplateSpecializationInfo()) { @@ -7570,6 +7568,48 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } } +namespace { + // Mark all of the declarations referenced + // FIXME: Not fully implemented yet! We need to have a better understanding + // of when we're entering + class MarkReferencedDecls : public RecursiveASTVisitor<MarkReferencedDecls> { + Sema &S; + SourceLocation Loc; + + public: + typedef RecursiveASTVisitor<MarkReferencedDecls> Inherited; + + MarkReferencedDecls(Sema &S, SourceLocation Loc) : S(S), Loc(Loc) { } + + bool VisitTemplateArgument(const TemplateArgument &Arg); + bool VisitRecordType(RecordType *T); + }; +} + +bool MarkReferencedDecls::VisitTemplateArgument(const TemplateArgument &Arg) { + if (Arg.getKind() == TemplateArgument::Declaration) { + S.MarkDeclarationReferenced(Loc, Arg.getAsDecl()); + } + + return Inherited::VisitTemplateArgument(Arg); +} + +bool MarkReferencedDecls::VisitRecordType(RecordType *T) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) { + const TemplateArgumentList &Args = Spec->getTemplateArgs(); + return VisitTemplateArguments(Args.getFlatArgumentList(), + Args.flat_size()); + } + + return false; +} + +void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) { + MarkReferencedDecls Marker(*this, Loc); + Marker.Visit(Context.getCanonicalType(T)); +} + /// \brief Emit a diagnostic that describes an effect on the run-time behavior /// of the program being compiled. /// @@ -7698,3 +7738,17 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { return false; } + +Sema::OwningExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, + ExprArg SubExpr) { + Expr *Sub = SubExpr.takeAs<Expr>(); + if (!Sub) + return ExprError(); + + if (CheckBooleanCondition(Sub, Loc)) { + Sub->Destroy(Context); + return ExprError(); + } + + return Owned(Sub); +} diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 425fc2d15aa5..97de96aacbbd 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -261,7 +261,8 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, Range = SourceRange(NameLoc); } - return CheckTypenameType(ETK_None, NNS, II, Range).getAsOpaquePtr(); + return CheckTypenameType(ETK_None, NNS, II, SourceLocation(), + Range, NameLoc).getAsOpaquePtr(); } if (ObjectTypePtr) @@ -314,8 +315,12 @@ Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, // When typeid is applied to an expression other than an lvalue of a // polymorphic class type [...] [the] expression is an unevaluated // operand. [...] - if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) + if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) { isUnevaluatedOperand = false; + + // We require a vtable to query the type at run time. + MarkVTableUsed(TypeidLoc, RecordD); + } } // C++ [expr.typeid]p4: @@ -437,14 +442,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. + // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p34. InitializedEntity Entity = - InitializedEntity::InitializeException(ThrowLoc, E->getType()); + InitializedEntity::InitializeException(ThrowLoc, E->getType(), + /*NRVO=*/false); OwningExprResult Res = PerformCopyInitialization(Entity, SourceLocation(), Owned(E)); if (Res.isInvalid()) return true; E = Res.takeAs<Expr>(); + + // If we are throwing a polymorphic class type or pointer thereof, + // exception handling will make use of the vtable. + if (const RecordType *RecordTy = Ty->getAs<RecordType>()) + MarkVTableUsed(ThrowLoc, cast<CXXRecordDecl>(RecordTy->getDecl())); + return false; } @@ -453,10 +466,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. - if (!isa<FunctionDecl>(CurContext)) - return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); - - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) + DeclContext *DC = getFunctionLevelDeclContext(); + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) if (MD->isInstance()) return Owned(new (Context) CXXThisExpr(ThisLoc, MD->getThisType(Context), @@ -668,10 +679,19 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (CheckAllocatedType(AllocType, TypeLoc, TypeRange)) return ExprError(); - QualType ResultType = Context.getPointerType(AllocType); + // Per C++0x [expr.new]p5, the type being constructed may be a + // typedef of an array type. + if (!ArraySizeE.get()) { + if (const ConstantArrayType *Array + = Context.getAsConstantArrayType(AllocType)) { + ArraySizeE = Owned(new (Context) IntegerLiteral(Array->getSize(), + Context.getSizeType(), + TypeRange.getEnd())); + AllocType = Array->getElementType(); + } + } - // That every array dimension except the first is constant was already - // checked by the type check above. + QualType ResultType = Context.getPointerType(AllocType); // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." @@ -739,7 +759,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); // Array 'new' can't have any initializers. - if (NumConsArgs && ArraySize) { + if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) { SourceRange InitRange(ConsArgs[0]->getLocStart(), ConsArgs[NumConsArgs - 1]->getLocEnd()); @@ -1173,7 +1193,7 @@ void Sema::DeclareGlobalNewDelete() { if (!StdBadAlloc) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. - StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class, + StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, StdNamespace, SourceLocation(), &PP.getIdentifierTable().get("bad_alloc"), @@ -1378,7 +1398,13 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, << Type << Ex->getSourceRange()); QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); - if (Pointee->isFunctionType() || Pointee->isVoidType()) + if (Pointee->isVoidType() && !isSFINAEContext()) { + // The C++ standard bans deleting a pointer to a non-object type, which + // effectively bans deletion of "void*". However, most compilers support + // this, so we treat it as a warning unless we're in a SFINAE context. + Diag(StartLoc, diag::ext_delete_void_ptr_operand) + << Type << Ex->getSourceRange(); + } else if (Pointee->isFunctionType() || Pointee->isVoidType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); else if (!Pointee->isDependentType() && @@ -1437,7 +1463,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, /// \brief Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. -Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) { +Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, + SourceLocation StmtLoc, + bool ConvertToBoolean) { QualType T = ConditionVar->getType(); // C++ [stmt.select]p2: @@ -1451,9 +1479,15 @@ Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) { diag::err_invalid_use_of_array_type) << ConditionVar->getSourceRange()); - return Owned(DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, - ConditionVar->getLocation(), - ConditionVar->getType().getNonReferenceType())); + Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, + ConditionVar->getLocation(), + ConditionVar->getType().getNonReferenceType()); + if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) { + Condition->Destroy(Context); + return ExprError(); + } + + return Owned(Condition); } /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. @@ -1748,10 +1782,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ImpCastExprToType(From, ToType, CastExpr::CK_FloatingToIntegral); break; - case ICK_Complex_Real: - ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); - break; - case ICK_Compatible_Conversion: ImpCastExprToType(From, ToType, CastExpr::CK_NoOp); break; @@ -1794,18 +1824,41 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; } - case ICK_Derived_To_Base: + case ICK_Derived_To_Base: { + CXXBaseSpecifierArray BasePath; if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), - From->getSourceRange(), 0, + From->getSourceRange(), + &BasePath, IgnoreBaseAccess)) return true; + ImpCastExprToType(From, ToType.getNonReferenceType(), - CastExpr::CK_DerivedToBase); + CastExpr::CK_DerivedToBase, + /*isLvalue=*/(From->getType()->isRecordType() && + From->isLvalue(Context) == Expr::LV_Valid), + BasePath); + break; + } + + case ICK_Vector_Conversion: + ImpCastExprToType(From, ToType, CastExpr::CK_BitCast); + break; + + case ICK_Vector_Splat: + ImpCastExprToType(From, ToType, CastExpr::CK_VectorSplat); break; - default: + case ICK_Complex_Real: + ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); + break; + + case ICK_Lvalue_To_Rvalue: + case ICK_Array_To_Pointer: + case ICK_Function_To_Pointer: + case ICK_Qualification: + case ICK_Num_Conversion_Kinds: assert(false && "Improper second standard conversion"); break; } @@ -1828,7 +1881,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; default: - assert(false && "Improper second standard conversion"); + assert(false && "Improper third standard conversion"); break; } @@ -2113,8 +2166,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LHS->isTypeDependent() || RHS->isTypeDependent()) return Context.DependentTy; - CheckSignCompare(LHS, RHS, QuestionLoc); - // C++0x 5.16p2 // If either the second or the third operand has type (cv) void, ... QualType LTy = LHS->getType(); @@ -2218,9 +2269,36 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // After those conversions, one of the following shall hold: // -- The second and third operands have the same type; the result - // is of that type. - if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) + // is of that type. If the operands have class type, the result + // is a prvalue temporary of the result type, which is + // copy-initialized from either the second operand or the third + // operand depending on the value of the first operand. + if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { + if (LTy->isRecordType()) { + // The operands have class type. Make a temporary copy. + InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); + OwningExprResult LHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(LHS)); + if (LHSCopy.isInvalid()) + return QualType(); + + OwningExprResult RHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(RHS)); + if (RHSCopy.isInvalid()) + return QualType(); + + LHS = LHSCopy.takeAs<Expr>(); + RHS = RHSCopy.takeAs<Expr>(); + } + return LTy; + } + + // Extension: conditional operator involving vector types. + if (LTy->isVectorType() || RTy->isVectorType()) + return CheckVectorOperands(QuestionLoc, LHS, RHS); // -- The second and third operands have arithmetic or enumeration type; // the usual arithmetic conversions are performed to bring them to a @@ -2529,6 +2607,9 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) { assert(SubExpr && "sub expression can't be null!"); + // Check any implicit conversions within the expression. + CheckImplicitConversions(SubExpr); + unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; assert(ExprTemporaries.size() >= FirstTemporary); if (ExprTemporaries.size() == FirstTemporary) @@ -2713,12 +2794,12 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, if (DestructedTypeInfo) { QualType DestructedType = DestructedTypeInfo->getType(); SourceLocation DestructedTypeStart - = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(); + = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!DestructedType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << BaseE->getSourceRange() - << DestructedTypeInfo->getTypeLoc().getSourceRange(); + << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); // Recover by setting the destructed type to the object type. DestructedType = ObjectType; @@ -2740,10 +2821,10 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameType(ScopeType, ObjectType)) { - Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(), + Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) << ObjectType << ScopeType << BaseE->getSourceRange() - << ScopeTypeInfo->getTypeLoc().getSourceRange(); + << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); ScopeType = QualType(); ScopeTypeInfo = 0; @@ -2943,6 +3024,8 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs<Expr>(); if (FullExpr) FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr); - + else + return ExprError(); + return Owned(FullExpr); } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index db9a2e238f95..695a1beca15e 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -254,7 +254,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, if (Args[i]->isTypeDependent()) continue; - IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod); + IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0); } } else { // Check for extra arguments to non-variadic methods. @@ -718,14 +718,12 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, } SourceLocation Loc = SuperLoc.isValid()? SuperLoc - : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin(); + : ReceiverTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); // Find the class to which we are sending this message. ObjCInterfaceDecl *Class = 0; - if (const ObjCInterfaceType *ClassType - = ReceiverType->getAs<ObjCInterfaceType>()) - Class = ClassType->getDecl(); - else { + const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>(); + if (!ClassType || !(Class = ClassType->getInterface())) { Diag(Loc, diag::err_invalid_receiver_class_message) << ReceiverType; return ExprError(); @@ -766,15 +764,17 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, } // Construct the appropriate ObjCMessageExpr. + Expr *Result; if (SuperLoc.isValid()) - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/false, - ReceiverType, Sel, Method, Args, - NumArgs, RBracLoc)); - - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - ReceiverTypeInfo, Sel, Method, Args, - NumArgs, RBracLoc)); + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/false, + ReceiverType, Sel, Method, Args, + NumArgs, RBracLoc); + else + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + ReceiverTypeInfo, Sel, Method, Args, + NumArgs, RBracLoc); + return MaybeBindToTemporary(Result); } // ActOnClassMessage - used for both unary and keyword messages. @@ -976,6 +976,21 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, ImpCastExprToType(Receiver, Context.getObjCIdType(), CastExpr::CK_IntegralToPointer); ReceiverType = Receiver->getType(); + } + else if (getLangOptions().CPlusPlus && + !PerformContextuallyConvertToObjCId(Receiver)) { + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) { + Receiver = ICE->getSubExpr(); + ReceiverType = Receiver->getType(); + } + return BuildInstanceMessage(Owned(Receiver), + ReceiverType, + SuperLoc, + Sel, + Method, + LBracLoc, + RBracLoc, + move(ArgsIn)); } else { // Reject other random receiver types (e.g. structs). Diag(Loc, diag::err_bad_receiver_type) @@ -994,14 +1009,16 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, return ExprError(); // Construct the appropriate ObjCMessageExpr instance. + Expr *Result; if (SuperLoc.isValid()) - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/true, - ReceiverType, Sel, Method, - Args, NumArgs, RBracLoc)); - - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, - Sel, Method, Args, NumArgs, RBracLoc)); + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/true, + ReceiverType, Sel, Method, + Args, NumArgs, RBracLoc); + else + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, + Sel, Method, Args, NumArgs, RBracLoc); + return MaybeBindToTemporary(Result); } // ActOnInstanceMessage - used for both unary and keyword messages. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 0aa344617763..20f0c79c48c6 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -624,7 +624,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, } else if (DeclType->isReferenceType()) { CheckReferenceType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); - } else if (DeclType->isObjCInterfaceType()) { + } else if (DeclType->isObjCObjectType()) { SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class) << DeclType; hadError = true; @@ -1984,6 +1984,26 @@ DeclaratorDecl *InitializedEntity::getDecl() const { return 0; } +bool InitializedEntity::allowsNRVO() const { + switch (getKind()) { + case EK_Result: + case EK_Exception: + return LocAndNRVO.NRVO; + + case EK_Variable: + case EK_Parameter: + case EK_Member: + case EK_New: + case EK_Temporary: + case EK_Base: + case EK_ArrayElement: + case EK_VectorElement: + break; + } + + return false; +} + //===----------------------------------------------------------------------===// // Initialization sequence //===----------------------------------------------------------------------===// @@ -2034,6 +2054,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_ReferenceBindingToInitList: case FK_InitListBadDestinationType: case FK_DefaultInitOfConst: + case FK_Incomplete: return false; case FK_ReferenceInitOverloadFailed: @@ -2245,11 +2266,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; const RecordType *T1RecordType = 0; - if (AllowRValues && (T1RecordType = T1->getAs<RecordType>())) { + if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) && + !S.RequireCompleteType(Kind.getLocation(), T1, 0)) { // The type we're converting to is a class type. Enumerate its constructors // to see if there is a suitable conversion. CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl()); - DeclarationName ConstructorName = S.Context.DeclarationNames.getCXXConstructorName( S.Context.getCanonicalType(T1).getUnqualifiedType()); @@ -2281,7 +2302,9 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, } } - if (const RecordType *T2RecordType = T2->getAs<RecordType>()) { + const RecordType *T2RecordType = 0; + if ((T2RecordType = T2->getAs<RecordType>()) && + !S.RequireCompleteType(Kind.getLocation(), T2, 0)) { // The type we're converting from is a class type, enumerate its conversion // functions. CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl()); @@ -2627,7 +2650,7 @@ static void TryConstructorInitialization(Sema &S, // The type we're constructing needs to be complete. if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { - Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); + Sequence.SetFailed(InitializationSequence::FK_Incomplete); return; } @@ -2740,8 +2763,8 @@ static void TryValueInitialization(Sema &S, // without a user-provided constructor, then the object is // zero-initialized and, if T’s implicitly-declared default // constructor is non-trivial, that constructor is called. - if ((ClassDecl->getTagKind() == TagDecl::TK_class || - ClassDecl->getTagKind() == TagDecl::TK_struct) && + if ((ClassDecl->getTagKind() == TTK_Class || + ClassDecl->getTagKind() == TTK_Struct) && !ClassDecl->hasTrivialConstructor()) { Sequence.AddZeroInitializationStep(Entity.getType()); return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); @@ -3240,9 +3263,9 @@ static Sema::OwningExprResult CopyObject(Sema &S, // directly into the target of the omitted copy/move // // Note that the other three bullets are handled elsewhere. Copy - // elision for return statements and throw expressions are (FIXME: - // not yet) handled as part of constructor initialization, while - // copy elision for exception handlers is handled by the run-time. + // elision for return statements and throw expressions are handled as part + // of constructor initialization, while copy elision for exception handlers + // is handled by the run-time. bool Elidable = CurInitExpr->isTemporaryObject() && S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType()); SourceLocation Loc; @@ -3517,6 +3540,7 @@ InitializationSequence::Perform(Sema &S, // Overload resolution determined which function invoke; update the // initializer to reflect that choice. S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl); + S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()); CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function.FoundDecl, Step->Function.Function); @@ -3537,6 +3561,15 @@ InitializationSequence::Perform(Sema &S, &BasePath, IgnoreBaseAccess)) return S.ExprError(); + if (S.BasePathInvolvesVirtualBase(BasePath)) { + QualType T = SourceType; + if (const PointerType *Pointer = T->getAs<PointerType>()) + T = Pointer->getPointeeType(); + if (const RecordType *RecordTy = T->getAs<RecordType>()) + S.MarkVTableUsed(CurInitExpr->getLocStart(), + cast<CXXRecordDecl>(RecordTy->getDecl())); + } + CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type, CastExpr::CK_DerivedToBase, (Expr*)CurInit.release(), @@ -3619,6 +3652,7 @@ InitializationSequence::Perform(Sema &S, S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, FoundFn.getAccess()); + S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); CastKind = CastExpr::CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); @@ -3633,6 +3667,7 @@ InitializationSequence::Perform(Sema &S, IsLvalue = Conversion->getResultType()->isLValueReferenceType(); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, FoundFn); + S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because @@ -3723,7 +3758,7 @@ InitializationSequence::Perform(Sema &S, unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Step->Function.Function); - + // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); SourceLocation Loc = Kind.getLocation(); @@ -3760,11 +3795,21 @@ InitializationSequence::Perform(Sema &S, CXXConstructExpr::CK_VirtualBase : CXXConstructExpr::CK_NonVirtualBase; } - CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), - Constructor, - move_arg(ConstructorArgs), - ConstructorInitRequiresZeroInit, - ConstructKind); + + // If the entity allows NRVO, mark the construction as elidable + // unconditionally. + if (Entity.allowsNRVO()) + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, /*Elidable=*/true, + move_arg(ConstructorArgs), + ConstructorInitRequiresZeroInit, + ConstructKind); + else + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, + move_arg(ConstructorArgs), + ConstructorInitRequiresZeroInit, + ConstructKind); } if (CurInit.isInvalid()) return S.ExprError(); @@ -3772,6 +3817,7 @@ InitializationSequence::Perform(Sema &S, // Only check access if all of that succeeded. S.CheckConstructorAccess(Loc, Constructor, Entity, Step->Function.FoundDecl.getAccess()); + S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Loc); if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); @@ -4092,6 +4138,11 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << (bool)DestType->getAs<RecordType>(); } break; + + case FK_Incomplete: + S.RequireCompleteType(Kind.getLocation(), DestType, + diag::err_init_incomplete_type); + break; } PrintInitLocationNote(S, Entity); @@ -4170,6 +4221,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case FK_DefaultInitOfConst: OS << "default initialization of a const variable"; break; + + case FK_Incomplete: + OS << "initialization of incomplete type"; + break; } OS << '\n'; return; diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 5f2592fb77cf..a9064ede6d34 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -85,11 +85,16 @@ private: /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. DeclaratorDecl *VariableOrMember; - /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the - /// location of the 'return', 'throw', or 'new' keyword, - /// respectively. When Kind == EK_Temporary, the location where - /// the temporary is being created. - unsigned Location; + struct { + /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the + /// location of the 'return', 'throw', or 'new' keyword, + /// respectively. When Kind == EK_Temporary, the location where + /// the temporary is being created. + unsigned Location; + + /// \brief Whether the + bool NRVO; + } LocAndNRVO; /// \brief When Kind == EK_Base, the base specifier that provides the /// base class. The lower bit specifies whether the base is an inherited @@ -116,8 +121,13 @@ private: /// \brief Create the initialization entity for the result of a /// function, throwing an object, performing an explicit cast, or /// initializing a parameter for which there is no declaration. - InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type) - : Kind(Kind), Parent(0), Type(Type), Location(Loc.getRawEncoding()) { } + InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, + bool NRVO = false) + : Kind(Kind), Parent(0), Type(Type) + { + LocAndNRVO.Location = Loc.getRawEncoding(); + LocAndNRVO.NRVO = NRVO; + } /// \brief Create the initialization entity for a member subobject. InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent) @@ -152,14 +162,14 @@ public: /// \brief Create the initialization entity for the result of a function. static InitializedEntity InitializeResult(SourceLocation ReturnLoc, - QualType Type) { - return InitializedEntity(EK_Result, ReturnLoc, Type); + QualType Type, bool NRVO) { + return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); } /// \brief Create the initialization entity for an exception object. static InitializedEntity InitializeException(SourceLocation ThrowLoc, - QualType Type) { - return InitializedEntity(EK_Exception, ThrowLoc, Type); + QualType Type, bool NRVO) { + return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO); } /// \brief Create the initialization entity for an object allocated via new. @@ -208,6 +218,10 @@ public: /// initialized. DeclaratorDecl *getDecl() const; + /// \brief Determine whether this initialization allows the named return + /// value optimization, which also applies to thrown objects. + bool allowsNRVO() const; + /// \brief Retrieve the base specifier. CXXBaseSpecifier *getBaseSpecifier() const { assert(getKind() == EK_Base && "Not a base specifier"); @@ -224,14 +238,14 @@ public: /// the result of a function call. SourceLocation getReturnLoc() const { assert(getKind() == EK_Result && "No 'return' location!"); - return SourceLocation::getFromRawEncoding(Location); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } /// \brief Determine the location of the 'throw' keyword when initializing /// an exception object. SourceLocation getThrowLoc() const { assert(getKind() == EK_Exception && "No 'throw' location!"); - return SourceLocation::getFromRawEncoding(Location); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } /// \brief If this is already the initializer for an array or vector @@ -530,7 +544,9 @@ public: /// \brief Overloaded for initialization by constructor failed. FK_ConstructorOverloadFailed, /// \brief Default-initialization of a 'const' object. - FK_DefaultInitOfConst + FK_DefaultInitOfConst, + /// \brief Initialization of an incomplete type. + FK_Incomplete }; private: diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 337a4a3ce3f7..4555a86e01c8 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -665,6 +665,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // DeclContext *OutsideOfTemplateParamDC = 0; for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { + DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); + // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { @@ -675,10 +677,12 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { } if (Found) { R.resolveKind(); + if (S->isClassScope()) + if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx)) + R.setNamingClass(Record); return true; } - 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 @@ -761,10 +765,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // context as well as walking through the scopes. for (; S; S = S->getParent()) { - DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity()); - if (Ctx && Ctx->isTransparentContext()) - continue; - // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { @@ -778,21 +778,57 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { } } - // 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."); + if (Found && S->isTemplateParamScope()) { + R.resolveKind(); + return true; + } - // Look into context considering using-directives. - if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) - Found = true; + 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; - if (Found) { - R.resolveKind(); - return true; + 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. + if (Ctx->isTransparentContext()) + continue; + + // 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 (!(Found && S && S->isTemplateParamScope())) { + assert(Ctx->isFileContext() && + "We should have been looking only at file context here already."); + + // Look into context considering using-directives. + if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) + Found = true; + } + + if (Found) { + R.resolveKind(); + return true; + } + + if (R.isForRedeclaration() && !Ctx->isTransparentContext()) + return false; + } } if (R.isForRedeclaration() && Ctx && !Ctx->isTransparentContext()) @@ -2580,6 +2616,12 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, WantExpressionKeywords = true; WantCXXNamedCasts = true; WantRemainingKeywords = true; + + if (ObjCMethodDecl *Method = getCurMethodDecl()) + if (Method->getClassInterface() && + Method->getClassInterface()->getSuperClass()) + Consumer.addKeywordResult(Context, "super"); + break; case CTC_NoKeywords: @@ -2646,7 +2688,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, Consumer.addKeywordResult(Context, "typeof"); } - if (WantCXXNamedCasts) { + if (WantCXXNamedCasts && getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "const_cast"); Consumer.addKeywordResult(Context, "dynamic_cast"); Consumer.addKeywordResult(Context, "reinterpret_cast"); @@ -2776,6 +2818,25 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, BestIvarOrPropertyDecl = 0; FoundIvarOrPropertyDecl = false; Consumer.clear_decls(); + } else if (CTC == CTC_ObjCMessageReceiver && + (*Consumer.keyword_begin())->isStr("super")) { + // In an Objective-C message send, give the "super" keyword a slight + // edge over entities not in function or method scope. + for (TypoCorrectionConsumer::iterator I = Consumer.begin(), + IEnd = Consumer.end(); + I != IEnd; ++I) { + if ((*I)->getDeclName() == BestName) { + if ((*I)->getDeclContext()->isFunctionOrMethod()) + return DeclarationName(); + } + } + + // Everything found was outside a function or method; the 'super' + // keyword takes precedence. + BestIvarOrPropertyDecl = 0; + FoundIvarOrPropertyDecl = false; + Consumer.clear_decls(); + BestName = *Consumer.keyword_begin(); } else { // Name collision; we will not correct typos. return DeclarationName(); diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index b73739fc5551..4c89a118bc9a 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -13,6 +13,8 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" +#include "clang/AST/ExprObjC.h" using namespace clang; @@ -119,7 +121,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CCPrimary, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, - Attributes, T, MethodImplKind); + Attributes, T, MethodImplKind, DC); // 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. @@ -189,7 +191,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, const bool isReadWrite, const unsigned Attributes, QualType T, - tok::ObjCKeywordKind MethodImplKind){ + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC){ IdentifierInfo *PropertyId = FD.D.getIdentifier(); @@ -197,19 +200,16 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, // 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"), AtLoc)) - if (IDecl->ClassImplementsProtocol(PNSCopying, true)) - Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId; - } + if (const ObjCObjectPointerType *ObjPtrTy = + T->getAs<ObjCObjectPointerType>()) { + ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); + if (IDecl) + if (ObjCProtocolDecl* PNSCopying = + LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc)) + if (IDecl->ClassImplementsProtocol(PNSCopying, true)) + Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId; } - if (T->isObjCInterfaceType()) + if (T->isObjCObjectType()) Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object); DeclContext *DC = cast<DeclContext>(CDecl); @@ -223,8 +223,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, Diag(prevDecl->getLocation(), diag::note_property_declare); PDecl->setInvalidDecl(); } - else + else { DC->addDecl(PDecl); + if (lexicalDC) + PDecl->setLexicalDeclContext(lexicalDC); + } if (T->isArrayType() || T->isFunctionType()) { Diag(AtLoc, diag::err_property_type) << T; @@ -275,7 +278,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, /// builds the AST node for a property implementation declaration; declared /// as @synthesize or @dynamic. /// -Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, +Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, SourceLocation PropertyLoc, bool Synthesize, DeclPtrTy ClassCatImpDecl, @@ -379,7 +383,16 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, // Check that type of property and its ivar are type compatible. if (PropType != IvarType) { - if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { + bool compat = false; + if (isa<ObjCObjectPointerType>(PropType) + && isa<ObjCObjectPointerType>(IvarType)) + compat = + Context.canAssignObjCInterfaces( + PropType->getAs<ObjCObjectPointerType>(), + IvarType->getAs<ObjCObjectPointerType>()); + else + compat = (CheckAssignmentConstraints(PropType, IvarType) == Compatible); + if (!compat) { Diag(PropertyLoc, diag::error_property_ivar_type) << property->getDeclName() << PropType << Ivar->getDeclName() << IvarType; @@ -427,6 +440,55 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, ObjCPropertyImplDecl::Synthesize : ObjCPropertyImplDecl::Dynamic), Ivar); + if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { + getterMethod->createImplicitParams(Context, IDecl); + if (getLangOptions().CPlusPlus && Synthesize) { + // For Objective-C++, need to synthesize the AST for the IVAR object to be + // returned by the getter as it must conform to C++'s copy-return rules. + // FIXME. Eventually we want to do this for Objective-C as well. + ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl(); + DeclRefExpr *SelfExpr = + new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(), + SourceLocation()); + Expr *IvarRefExpr = + new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, + SelfExpr, true, true); + OwningExprResult Res = + PerformCopyInitialization(InitializedEntity::InitializeResult( + SourceLocation(), + getterMethod->getResultType(), + /*NRVO=*/false), + SourceLocation(), + Owned(IvarRefExpr)); + if (!Res.isInvalid()) { + Expr *ResExpr = Res.takeAs<Expr>(); + if (ResExpr) + ResExpr = MaybeCreateCXXExprWithTemporaries(ResExpr); + PIDecl->setGetterCXXConstructor(ResExpr); + } + } + } + if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { + setterMethod->createImplicitParams(Context, IDecl); + if (getLangOptions().CPlusPlus && Synthesize) { + // FIXME. Eventually we want to do this for Objective-C as well. + ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl(); + DeclRefExpr *SelfExpr = + new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(), + SourceLocation()); + Expr *lhs = + new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, + SelfExpr, true, true); + ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); + ParmVarDecl *Param = (*P); + Expr *rhs = new (Context) DeclRefExpr(Param,Param->getType(), + SourceLocation()); + OwningExprResult Res = BuildBinOp(S, SourceLocation(), + BinaryOperator::Assign, lhs, rhs); + PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>()); + } + } + if (IC) { if (Synthesize) if (ObjCPropertyImplDecl *PPIDecl = @@ -751,6 +813,47 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, } } +/// CollectClassPropertyImplementations - This routine collects list of +/// properties to be implemented in the class. This includes, class's +/// and its conforming protocols' properties. +static void CollectClassPropertyImplementations(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; + } + for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), + E = IDecl->protocol_end(); PI != E; ++PI) + CollectClassPropertyImplementations((*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); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + CollectClassPropertyImplementations((*PI), PropMap); + } +} + +/// CollectSuperClassPropertyImplementations - This routine collects list of +/// properties to be implemented in super class(s) and also coming from their +/// conforming protocols. +static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { + if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) { + while (SDecl) { + CollectClassPropertyImplementations(SDecl, PropMap); + SDecl = SDecl->getSuperClass(); + } + } +} + /// ProtocolConformsToSuperClass - Returns true if class's given protocol /// conforms to one of its super class's protocols. bool Sema::ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl, @@ -817,8 +920,36 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, return 0; } +/// DefaultSynthesizeProperties - This routine default synthesizes all +/// properties which must be synthesized in class's @implementation. +void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl *IDecl) { + + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; + CollectClassPropertyImplementations(IDecl, PropMap); + if (PropMap.empty()) + return; + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap; + CollectSuperClassPropertyImplementations(IDecl, SuperPropMap); + + for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator + P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { + ObjCPropertyDecl *Prop = P->second; + // If property to be implemented in the super class, ignore. + if (SuperPropMap[Prop->getIdentifier()]) + continue; + // Is there a matching propery synthesize/dynamic? + if (Prop->isInvalidDecl() || + Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || + IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) + continue; + ActOnPropertyImplDecl(S, IMPDecl->getLocation(), IMPDecl->getLocation(), + true, DeclPtrTy::make(IMPDecl), + Prop->getIdentifier(), Prop->getIdentifier()); + } +} -void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, +void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet<Selector>& InsMap) { llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; @@ -840,14 +971,6 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || PropImplMap.count(Prop)) continue; - if (LangOpts.ObjCNonFragileABI2 && !isa<ObjCCategoryImplDecl>(IMPDecl)) { - ActOnPropertyImplDecl(IMPDecl->getLocation(), - IMPDecl->getLocation(), - true, DeclPtrTy::make(IMPDecl), - Prop->getIdentifier(), - Prop->getIdentifier()); - continue; - } if (!InsMap.count(Prop->getGetterName())) { Diag(Prop->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? @@ -954,6 +1077,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCMethodDecl::Optional : ObjCMethodDecl::Required); CD->addDecl(GetterMethod); + // FIXME: Eventually this shouldn't be needed, as the lexical context + // and the real context should be the same. + if (DeclContext *lexicalDC = property->getLexicalDeclContext()) + GetterMethod->setLexicalDeclContext(lexicalDC); + } else // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation @@ -987,6 +1115,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, 0); SetterMethod->setMethodParams(Context, &Argument, 1, 1); CD->addDecl(SetterMethod); + // FIXME: Eventually this shouldn't be needed, as the lexical context + // and the real context should be the same. + if (DeclContext *lexicalDC = property->getLexicalDeclContext()) + SetterMethod->setLexicalDeclContext(lexicalDC); } else // A user declared setter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index b87fa7d51ea1..2754d443b25a 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -52,6 +52,8 @@ GetConversionCategory(ImplicitConversionKind Kind) { ICC_Conversion, ICC_Conversion, ICC_Conversion, + ICC_Conversion, + ICC_Conversion, ICC_Conversion }; return Category[(int)Kind]; @@ -80,6 +82,8 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Conversion, ICR_Conversion, ICR_Conversion, + ICR_Conversion, + ICR_Conversion, ICR_Complex_Real_Conversion }; return Rank[(int)Kind]; @@ -102,12 +106,14 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Floating conversion", "Complex conversion", "Floating-integral conversion", - "Complex-real conversion", "Pointer conversion", "Pointer-to-member conversion", "Boolean conversion", "Compatible-types conversion", - "Derived-to-base conversion" + "Derived-to-base conversion", + "Vector conversion", + "Vector splat", + "Complex-real conversion" }; return Name[Kind]; } @@ -275,7 +281,194 @@ AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) { new (&conversions()) ConversionSet(O.conversions()); } +namespace { + // Structure used by OverloadCandidate::DeductionFailureInfo to store + // template parameter and template argument information. + struct DFIParamWithArguments { + TemplateParameter Param; + TemplateArgument FirstArg; + TemplateArgument SecondArg; + }; +} + +/// \brief Convert from Sema's representation of template deduction information +/// to the form used in overload-candidate information. +OverloadCandidate::DeductionFailureInfo +static MakeDeductionFailureInfo(ASTContext &Context, + Sema::TemplateDeductionResult TDK, + Sema::TemplateDeductionInfo &Info) { + OverloadCandidate::DeductionFailureInfo Result; + Result.Result = static_cast<unsigned>(TDK); + Result.Data = 0; + switch (TDK) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + break; + + case Sema::TDK_Incomplete: + case Sema::TDK_InvalidExplicitArguments: + Result.Data = Info.Param.getOpaqueValue(); + break; + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: { + // FIXME: Should allocate from normal heap so that we can free this later. + DFIParamWithArguments *Saved = new (Context) DFIParamWithArguments; + Saved->Param = Info.Param; + Saved->FirstArg = Info.FirstArg; + Saved->SecondArg = Info.SecondArg; + Result.Data = Saved; + break; + } + + case Sema::TDK_SubstitutionFailure: + Result.Data = Info.take(); + break; + + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return Result; +} + +void OverloadCandidate::DeductionFailureInfo::Destroy() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_Incomplete: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_InvalidExplicitArguments: + break; + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + // FIXME: Destroy the data? + Data = 0; + break; + case Sema::TDK_SubstitutionFailure: + // FIXME: Destroy the template arugment list? + Data = 0; + break; + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } +} + +TemplateParameter +OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_SubstitutionFailure: + return TemplateParameter(); + + case Sema::TDK_Incomplete: + case Sema::TDK_InvalidExplicitArguments: + return TemplateParameter::getFromOpaqueValue(Data); + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + return static_cast<DFIParamWithArguments*>(Data)->Param; + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return TemplateParameter(); +} + +TemplateArgumentList * +OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_Incomplete: + case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + return 0; + + case Sema::TDK_SubstitutionFailure: + return static_cast<TemplateArgumentList*>(Data); + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return 0; +} + +const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_Incomplete: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_SubstitutionFailure: + return 0; + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + return &static_cast<DFIParamWithArguments*>(Data)->FirstArg; + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return 0; +} + +const TemplateArgument * +OverloadCandidate::DeductionFailureInfo::getSecondArg() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_Incomplete: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_SubstitutionFailure: + return 0; + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + return &static_cast<DFIParamWithArguments*>(Data)->SecondArg; + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return 0; +} + +void OverloadCandidateSet::clear() { + inherited::clear(); + Functions.clear(); +} + // IsOverload - Determine whether the given New declaration is an // overload of the declarations in Old. This routine returns false if // New and Old cannot be overloaded, e.g., if New has the same @@ -586,6 +779,48 @@ static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, ResultTy = FromType; return true; } + +/// \brief Determine whether the conversion from FromType to ToType is a valid +/// vector conversion. +/// +/// \param ICK Will be set to the vector conversion kind, if this is a vector +/// conversion. +static bool IsVectorConversion(ASTContext &Context, QualType FromType, + QualType ToType, ImplicitConversionKind &ICK) { + // We need at least one of these types to be a vector type to have a vector + // conversion. + if (!ToType->isVectorType() && !FromType->isVectorType()) + return false; + + // Identical types require no conversions. + if (Context.hasSameUnqualifiedType(FromType, ToType)) + return false; + + // There are no conversions between extended vector types, only identity. + if (ToType->isExtVectorType()) { + // There are no conversions between extended vector types other than the + // identity conversion. + if (FromType->isExtVectorType()) + return false; + + // Vector splat from any arithmetic type to a vector. + if (!FromType->isVectorType() && FromType->isArithmeticType()) { + ICK = ICK_Vector_Splat; + return true; + } + } + + // If lax vector conversions are permitted and the vector types are of the + // same size, we can perform the conversion. + if (Context.getLangOptions().LaxVectorConversions && + FromType->isVectorType() && ToType->isVectorType() && + Context.getTypeSize(FromType) == Context.getTypeSize(ToType)) { + ICK = ICK_Vector_Conversion; + return true; + } + + return false; +} /// IsStandardConversion - Determines whether there is a standard /// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the @@ -708,6 +943,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // For overloading in C, this can also be a "compatible-type" // conversion. bool IncompatibleObjC = false; + ImplicitConversionKind SecondICK = ICK_Identity; if (Context.hasSameUnqualifiedType(FromType, ToType)) { // The unqualified versions of the types are the same: there's no // conversion to do. @@ -769,10 +1005,14 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // Boolean conversions (C++ 4.12). SCS.Second = ICK_Boolean_Conversion; FromType = Context.BoolTy; + } else if (IsVectorConversion(Context, FromType, ToType, SecondICK)) { + SCS.Second = SecondICK; + FromType = ToType.getUnqualifiedType(); } else if (!getLangOptions().CPlusPlus && Context.typesAreCompatible(ToType, FromType)) { // Compatible conversions (Clang extension for C function overloading) SCS.Second = ICK_Compatible_Conversion; + FromType = ToType.getUnqualifiedType(); } else if (IsNoReturnConversion(Context, FromType, ToType, FromType)) { // Treat a conversion that strips "noreturn" as an identity conversion. SCS.Second = ICK_NoReturn_Adjustment; @@ -802,7 +1042,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, CanonTo = Context.getCanonicalType(ToType); if (CanonFrom.getLocalUnqualifiedType() == CanonTo.getLocalUnqualifiedType() && - CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()) { + (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers() + || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) { FromType = ToType; CanonFrom = CanonTo; } @@ -992,7 +1233,7 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, if (CanonToPointee.getLocalQualifiers() == Quals) { // ToType is exactly what we need. Return it. if (!ToType.isNull()) - return ToType; + return ToType.getUnqualifiedType(); // Build a pointer to ToPointee. It has the right qualifiers // already. @@ -1350,22 +1591,18 @@ bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType, if (ToType != FromType) { if (const PointerType *PTTo = ToType->getAs<PointerType>()) { if (const PointerType *PTFr = FromType->getAs<PointerType>()) - if (PTTo->getPointeeType()->isObjCQualifiedIdType() && - PTFr->getPointeeType()->isObjCQualifiedIdType() || - PTTo->getPointeeType()->isObjCQualifiedClassType() && - PTFr->getPointeeType()->isObjCQualifiedClassType()) + if ((PTTo->getPointeeType()->isObjCQualifiedIdType() && + PTFr->getPointeeType()->isObjCQualifiedIdType()) || + (PTTo->getPointeeType()->isObjCQualifiedClassType() && + PTFr->getPointeeType()->isObjCQualifiedClassType())) continue; } - else if (ToType->isObjCObjectPointerType() && - FromType->isObjCObjectPointerType()) { - QualType ToInterfaceTy = ToType->getPointeeType(); - QualType FromInterfaceTy = FromType->getPointeeType(); - if (const ObjCInterfaceType *OITTo = - ToInterfaceTy->getAs<ObjCInterfaceType>()) - if (const ObjCInterfaceType *OITFr = - FromInterfaceTy->getAs<ObjCInterfaceType>()) - if (OITTo->getDecl() == OITFr->getDecl()) - continue; + else if (const ObjCObjectPointerType *PTTo = + ToType->getAs<ObjCObjectPointerType>()) { + if (const ObjCObjectPointerType *PTFr = + FromType->getAs<ObjCObjectPointerType>()) + if (PTTo->getInterfaceDecl() == PTFr->getInterfaceDecl()) + continue; } return false; } @@ -1839,6 +2076,15 @@ compareStandardConversionSubsets(ASTContext &Context, ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; + // the identity conversion sequence is considered to be a subsequence of + // any non-identity conversion sequence + if (SCS1.ReferenceBinding == SCS2.ReferenceBinding) { + if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion()) + return ImplicitConversionSequence::Better; + else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion()) + return ImplicitConversionSequence::Worse; + } + if (SCS1.Second != SCS2.Second) { if (SCS1.Second == ICK_Identity) Result = ImplicitConversionSequence::Better; @@ -1954,8 +2200,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // Objective-C++: If one interface is more specific than the // other, it is the better one. - const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>(); - const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>(); + const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>(); + const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>(); if (FromIface1 && FromIface1) { if (Context.canAssignObjCInterfaces(FromIface2, FromIface1)) return ImplicitConversionSequence::Better; @@ -2161,10 +2407,10 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, QualType ToPointee2 = ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); - const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>(); - const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>(); - const ObjCInterfaceType* ToIface1 = ToPointee1->getAs<ObjCInterfaceType>(); - const ObjCInterfaceType* ToIface2 = ToPointee2->getAs<ObjCInterfaceType>(); + const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>(); + const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>(); + const ObjCObjectType* ToIface1 = ToPointee1->getAs<ObjCObjectType>(); + const ObjCObjectType* ToIface2 = ToPointee2->getAs<ObjCObjectType>(); // -- conversion of C* to B* is better than conversion of C* to A*, if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { @@ -2289,8 +2535,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // T1 is a base class of T2. if (UnqualT1 == UnqualT2) DerivedToBase = false; - else if (!RequireCompleteType(Loc, OrigT1, PDiag()) && - !RequireCompleteType(Loc, OrigT2, PDiag()) && + else if (!RequireCompleteType(Loc, OrigT2, PDiag()) && IsDerivedFrom(UnqualT2, UnqualT1)) DerivedToBase = true; else @@ -2724,6 +2969,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, /// TryContextuallyConvertToBool - Attempt to contextually convert the /// expression From to bool (C++0x [conv]p3). ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { + // FIXME: This is pretty broken. return TryImplicitConversion(From, Context.BoolTy, // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, @@ -2744,6 +2990,27 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { << From->getType() << From->getSourceRange(); return true; } + +/// TryContextuallyConvertToObjCId - Attempt to contextually convert the +/// expression From to 'id'. +ImplicitConversionSequence Sema::TryContextuallyConvertToObjCId(Expr *From) { + QualType Ty = Context.getObjCIdType(); + return TryImplicitConversion(From, Ty, + // FIXME: Are these flags correct? + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/true, + /*InOverloadResolution=*/false); +} + +/// PerformContextuallyConvertToObjCId - Perform a contextual conversion +/// of the expression From to 'id'. +bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) { + QualType Ty = Context.getObjCIdType(); + ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(From); + if (!ICS.isBad()) + return PerformImplicitConversion(From, Ty, ICS, AA_Converting); + return true; +} /// AddOverloadCandidate - Adds the given function to the set of /// candidate functions, using the given function call arguments. If @@ -3029,7 +3296,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, } } } - + /// \brief Add a C++ member function template as a candidate to the candidate /// set, using template argument deduction to produce an appropriate member /// function template specialization. @@ -3059,11 +3326,18 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, if (TemplateDeductionResult Result = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args, NumArgs, Specialization, Info)) { - // FIXME: Record what happened with template argument deduction, so - // that we can give the user a beautiful diagnostic. - (void)Result; - return; - } + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate &Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; + Candidate.Function = MethodTmpl->getTemplatedDecl(); + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_deduction; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Info); + return; + } // Add the function template specialization produced by template argument // deduction as a candidate. @@ -3110,10 +3384,8 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; - - // TODO: record more information about failed template arguments - Candidate.DeductionFailure.Result = Result; - Candidate.DeductionFailure.TemplateParameter = Info.Param.getOpaqueValue(); + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Info); return; } @@ -3260,9 +3532,16 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, ToType, Specialization, Info)) { - // FIXME: Record what happened with template argument deduction, so - // that we can give the user a beautiful diagnostic. - (void)Result; + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate &Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; + Candidate.Function = FunctionTemplate->getTemplatedDecl(); + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_deduction; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Info); return; } @@ -3504,6 +3783,10 @@ class BuiltinCandidateTypeSet { /// used in the built-in candidates. TypeSet EnumerationTypes; + /// \brief The set of vector types that will be used in the built-in + /// candidates. + TypeSet VectorTypes; + /// Sema - The semantic analysis instance where we are building the /// candidate type set. Sema &SemaRef; @@ -3545,6 +3828,9 @@ public: /// enumeration_end - Past the last enumeration type found; iterator enumeration_end() { return EnumerationTypes.end(); } + + iterator vector_begin() { return VectorTypes.begin(); } + iterator vector_end() { return VectorTypes.end(); } }; /// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to @@ -3677,6 +3963,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, return; } else if (Ty->isEnumeralType()) { EnumerationTypes.insert(Ty); + } else if (Ty->isVectorType()) { + VectorTypes.insert(Ty); } else if (AllowUserConversions) { if (const RecordType *TyRec = Ty->getAs<RecordType>()) { if (SemaRef.RequireCompleteType(Loc, Ty, 0)) { @@ -3841,21 +4129,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); BuiltinCandidateTypeSet CandidateTypes(*this); - if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual || - Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual || - Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal || - Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript || - Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus || - (Op == OO_Star && NumArgs == 1) || Op == OO_Conditional) { - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) - CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(), - OpLoc, - true, - (Op == OO_Exclaim || - Op == OO_AmpAmp || - Op == OO_PipePipe), - VisibleTypeConversionsQuals); - } + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(), + OpLoc, + true, + (Op == OO_Exclaim || + Op == OO_AmpAmp || + Op == OO_PipePipe), + VisibleTypeConversionsQuals); bool isComparison = false; switch (Op) { @@ -4019,6 +4300,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, QualType ArithTy = ArithmeticTypes[Arith]; AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); } + + // Extension: We also add these operators for vector types. + for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(), + VecEnd = CandidateTypes.vector_end(); + Vec != VecEnd; ++Vec) { + QualType VecTy = *Vec; + AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + } break; case OO_Tilde: @@ -4032,6 +4321,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, QualType IntTy = ArithmeticTypes[Int]; AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); } + + // Extension: We also add this operator for vector types. + for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(), + VecEnd = CandidateTypes.vector_end(); + Vec != VecEnd; ++Vec) { + QualType VecTy = *Vec; + AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + } break; case OO_New: @@ -4188,6 +4485,30 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); } } + + // Extension: Add the binary operators ==, !=, <, <=, >=, >, *, /, and the + // conditional operator for vector types. + for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(), + Vec1End = CandidateTypes.vector_end(); + Vec1 != Vec1End; ++Vec1) + for (BuiltinCandidateTypeSet::iterator + Vec2 = CandidateTypes.vector_begin(), + Vec2End = CandidateTypes.vector_end(); + Vec2 != Vec2End; ++Vec2) { + QualType LandR[2] = { *Vec1, *Vec2 }; + QualType Result; + if (isComparison) + Result = Context.BoolTy; + else { + if ((*Vec1)->isExtVectorType() || !(*Vec2)->isExtVectorType()) + Result = *Vec1; + else + Result = *Vec2; + } + + AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + } + break; case OO_Percent: @@ -4243,7 +4564,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, MemPtr != MemPtrEnd; ++MemPtr) AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2, CandidateSet); - // Fall through. + + // Fall through. case OO_PlusEqual: case OO_MinusEqual: @@ -4318,6 +4640,30 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, } } } + + // Extension: Add the binary operators =, +=, -=, *=, /= for vector types. + for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(), + Vec1End = CandidateTypes.vector_end(); + Vec1 != Vec1End; ++Vec1) + for (BuiltinCandidateTypeSet::iterator + Vec2 = CandidateTypes.vector_begin(), + Vec2End = CandidateTypes.vector_end(); + Vec2 != Vec2End; ++Vec2) { + QualType ParamTypes[2]; + ParamTypes[1] = *Vec2; + // Add this built-in operator as a candidate (VQ is empty). + ParamTypes[0] = Context.getLValueReferenceType(*Vec1); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + + // Add this built-in operator as a candidate (VQ is 'volatile'). + if (VisibleTypeConversionsQuals.hasVolatile()) { + ParamTypes[0] = Context.getVolatileType(*Vec1); + ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + } + } break; case OO_PercentEqual: @@ -4413,7 +4759,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, ParamTypes[0] = ParamTypes[1]; ParamTypes[1] = *Ptr; AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); - } + } break; case OO_ArrowStar: @@ -4901,16 +5247,21 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, unsigned MinParams = Fn->getMinRequiredArguments(); // at least / at most / exactly + // FIXME: variadic templates "at most" should account for parameter packs unsigned mode, modeCount; if (NumFormalArgs < MinParams) { - assert(Cand->FailureKind == ovl_fail_too_few_arguments); + assert((Cand->FailureKind == ovl_fail_too_few_arguments) || + (Cand->FailureKind == ovl_fail_bad_deduction && + Cand->DeductionFailure.Result == Sema::TDK_TooFewArguments)); if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic()) mode = 0; // "at least" else mode = 2; // "exactly" modeCount = MinParams; } else { - assert(Cand->FailureKind == ovl_fail_too_many_arguments); + assert((Cand->FailureKind == ovl_fail_too_many_arguments) || + (Cand->FailureKind == ovl_fail_bad_deduction && + Cand->DeductionFailure.Result == Sema::TDK_TooManyArguments)); if (MinParams != FnTy->getNumArgs()) mode = 1; // "at most" else @@ -4922,7 +5273,8 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) - << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs; + << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode + << modeCount << NumFormalArgs; } /// Diagnose a failed template-argument deduction. @@ -4930,34 +5282,86 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, Expr **Args, unsigned NumArgs) { FunctionDecl *Fn = Cand->Function; // pattern - TemplateParameter Param = TemplateParameter::getFromOpaqueValue( - Cand->DeductionFailure.TemplateParameter); - + TemplateParameter Param = Cand->DeductionFailure.getTemplateParameter(); + NamedDecl *ParamD; + (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) || + (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) || + (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>()); switch (Cand->DeductionFailure.Result) { case Sema::TDK_Success: llvm_unreachable("TDK_success while diagnosing bad deduction"); case Sema::TDK_Incomplete: { - NamedDecl *ParamD; - (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) || - (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) || - (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>()); assert(ParamD && "no parameter found for incomplete deduction result"); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction) << ParamD->getDeclName(); return; } - // TODO: diagnose these individually, then kill off - // note_ovl_candidate_bad_deduction, which is uselessly vague. - case Sema::TDK_InstantiationDepth: case Sema::TDK_Inconsistent: - case Sema::TDK_InconsistentQuals: - case Sema::TDK_SubstitutionFailure: - case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_InconsistentQuals: { + assert(ParamD && "no parameter found for inconsistent deduction result"); + int which = 0; + if (isa<TemplateTypeParmDecl>(ParamD)) + which = 0; + else if (isa<NonTypeTemplateParmDecl>(ParamD)) + which = 1; + else { + which = 2; + } + + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_inconsistent_deduction) + << which << ParamD->getDeclName() + << *Cand->DeductionFailure.getFirstArg() + << *Cand->DeductionFailure.getSecondArg(); + return; + } + + case Sema::TDK_InvalidExplicitArguments: + assert(ParamD && "no parameter found for invalid explicit arguments"); + if (ParamD->getDeclName()) + S.Diag(Fn->getLocation(), + diag::note_ovl_candidate_explicit_arg_mismatch_named) + << ParamD->getDeclName(); + else { + int index = 0; + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD)) + index = TTP->getIndex(); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(ParamD)) + index = NTTP->getIndex(); + else + index = cast<TemplateTemplateParmDecl>(ParamD)->getIndex(); + S.Diag(Fn->getLocation(), + diag::note_ovl_candidate_explicit_arg_mismatch_unnamed) + << (index + 1); + } + return; + case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: - case Sema::TDK_InvalidExplicitArguments: + DiagnoseArityMismatch(S, Cand, NumArgs); + return; + + case Sema::TDK_InstantiationDepth: + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth); + return; + + case Sema::TDK_SubstitutionFailure: { + std::string ArgString; + if (TemplateArgumentList *Args + = Cand->DeductionFailure.getTemplateArgumentList()) + ArgString = S.getTemplateArgumentBindingsText( + Fn->getDescribedFunctionTemplate()->getTemplateParameters(), + *Args); + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure) + << ArgString; + return; + } + + // TODO: diagnose these individually, then kill off + // note_ovl_candidate_bad_deduction, which is uselessly vague. + case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction); return; @@ -5500,8 +5904,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, assert(Result != MatchesCopy.end() && "no most-specialized template"); MarkDeclarationReferenced(From->getLocStart(), *Result); FoundResult = Matches[Result - MatchesCopy.begin()].first; - if (Complain) + if (Complain) { CheckUnresolvedAccess(*this, OvlExpr, FoundResult); + DiagnoseUseOfDecl(FoundResult, OvlExpr->getNameLoc()); + } return cast<FunctionDecl>(*Result); } @@ -5521,8 +5927,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Matches.size() == 1) { MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); FoundResult = Matches[0].first; - if (Complain) + if (Complain) { CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); + DiagnoseUseOfDecl(Matches[0].first, OvlExpr->getNameLoc()); + } return cast<FunctionDecl>(Matches[0].second); } @@ -5724,7 +6132,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); - if (SemaRef.DiagnoseEmptyLookup(S, SS, R)) + if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression)) return Destroy(SemaRef, Fn, Args, NumArgs); assert(!R.empty() && "lookup results empty despite recovery"); @@ -5801,6 +6209,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, case OR_Success: { FunctionDecl *FDecl = Best->Function; CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, ULE->getNameLoc()); Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } @@ -5885,9 +6294,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, OpLoc, - /*ADL*/ true, IsOverloaded(Fns)); - Fn->addDecls(Fns.begin(), Fns.end()); - + /*ADL*/ true, IsOverloaded(Fns), + Fns.begin(), Fns.end()); input.release(); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, &Args[0], NumArgs, @@ -5945,6 +6353,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, Input = (Expr *)input.get(); } + DiagnoseUseOfDecl(Best->FoundDecl, OpLoc); + // Determine the result type QualType ResultTy = FnDecl->getResultType().getNonReferenceType(); @@ -5958,7 +6368,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, ExprOwningPtr<CallExpr> TheCall(this, new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, Args, NumArgs, ResultTy, OpLoc)); - + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(), FnDecl)) return ExprError(); @@ -6056,9 +6466,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, OpLoc, - /*ADL*/ true, IsOverloaded(Fns)); - - Fn->addDecls(Fns.begin(), Fns.end()); + /*ADL*/ true, IsOverloaded(Fns), + Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args, 2, Context.DependentTy, @@ -6150,6 +6559,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Args[1] = RHS = Arg1.takeAs<Expr>(); } + DiagnoseUseOfDecl(Best->FoundDecl, OpLoc); + // Determine the result type QualType ResultTy = FnDecl->getType()->getAs<FunctionType>()->getResultType(); @@ -6252,7 +6663,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, LLoc, - /*ADL*/ true, /*Overloaded*/ false); + /*ADL*/ true, /*Overloaded*/ false, + UnresolvedSetIterator(), + UnresolvedSetIterator()); // Can't add any actual overloads yet Base.release(); @@ -6286,6 +6699,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // operator. CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, LLoc); // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); @@ -6452,6 +6866,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Method = cast<CXXMethodDecl>(Best->Function); FoundDecl = Best->FoundDecl; CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()); break; case OR_No_Viable_Function: @@ -6661,6 +7076,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, Best->Conversions[0].UserDefined.ConversionFunction); CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc); // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion @@ -6677,6 +7093,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, } CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc); // We found an overloaded operator(). Build a CXXOperatorCallExpr // that calls this method, using Object for the implicit object @@ -6767,7 +7184,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Promote the arguments (C99 6.5.2.2p7). for (unsigned i = NumArgsInProto; i != NumArgs; i++) { Expr *Arg = Args[i]; - IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod); + IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod, 0); TheCall->setArg(i + 1, Arg); } } @@ -6847,6 +7264,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { } CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, OpLoc); // Convert the object parameter. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 5e611113083f..eb4fc6581796 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -16,7 +16,9 @@ #define LLVM_CLANG_SEMA_OVERLOAD_H #include "clang/AST/Decl.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/AST/UnresolvedSet.h" #include "llvm/ADT/SmallPtrSet.h" @@ -60,6 +62,8 @@ namespace clang { ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12) ICK_Compatible_Conversion, ///< Conversions between compatible types in C99 ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics]) + ICK_Vector_Conversion, ///< Vector conversions + ICK_Vector_Splat, ///< A vector splat from an arithmetic type ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) ICK_Num_Conversion_Kinds ///< The number of conversion kinds }; @@ -173,6 +177,12 @@ namespace clang { } void setAsIdentityConversion(); + + bool isIdentityConversion() const { + return First == ICK_Identity && Second == ICK_Identity && + Third == ICK_Identity; + } + ImplicitConversionRank getRank() const; bool isPointerConversionToBool() const; bool isPointerConversionToVoidPointer(ASTContext& Context) const; @@ -529,8 +539,28 @@ namespace clang { // A Sema::TemplateDeductionResult. unsigned Result; - // A TemplateParameter. - void *TemplateParameter; + /// \brief Opaque pointer containing additional data about + /// this deduction failure. + void *Data; + + /// \brief Retrieve the template parameter this deduction failure + /// refers to, if any. + TemplateParameter getTemplateParameter(); + + /// \brief Retrieve the template argument list associated with this + /// deduction failure, if any. + TemplateArgumentList *getTemplateArgumentList(); + + /// \brief Return the first template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getFirstArg(); + + /// \brief Return the second template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getSecondArg(); + + /// \brief Free any memory associated with this deduction failure. + void Destroy(); }; union { @@ -562,6 +592,10 @@ namespace clang { llvm::SmallPtrSet<Decl *, 16> Functions; SourceLocation Loc; + + OverloadCandidateSet(const OverloadCandidateSet &); + OverloadCandidateSet &operator=(const OverloadCandidateSet &); + public: OverloadCandidateSet(SourceLocation Loc) : Loc(Loc) {} @@ -574,10 +608,9 @@ namespace clang { } /// \brief Clear out all of the candidates. - void clear() { - inherited::clear(); - Functions.clear(); - } + void clear(); + + ~OverloadCandidateSet() { clear(); } }; } // end namespace clang diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 9d6132d050c6..875b160d712f 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -30,7 +30,7 @@ using namespace clang; Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) { Expr *E = expr->takeAs<Expr>(); assert(E && "ActOnExprStmt(): missing expression"); - if (E->getType()->isObjCInterfaceType()) { + if (E->getType()->isObjCObjectType()) { if (LangOpts.ObjCNonFragileABI) Diag(E->getLocEnd(), diag::err_indirection_requires_nonfragile_object) << E->getType(); @@ -280,7 +280,7 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, VarDecl *ConditionVar = 0; if (CondVar.get()) { ConditionVar = CondVar.getAs<VarDecl>(); - CondResult = CheckConditionVariable(ConditionVar); + CondResult = CheckConditionVariable(ConditionVar, IfLoc, true); if (CondResult.isInvalid()) return StmtError(); } @@ -288,11 +288,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, if (!ConditionExpr) return StmtError(); - if (CheckBooleanCondition(ConditionExpr, IfLoc)) { - CondResult = ConditionExpr; - return StmtError(); - } - Stmt *thenStmt = ThenVal.takeAs<Stmt>(); DiagnoseUnusedExprResult(thenStmt); @@ -313,23 +308,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, thenStmt, ElseLoc, elseStmt)); } -Action::OwningStmtResult -Sema::ActOnStartOfSwitchStmt(FullExprArg cond, DeclPtrTy CondVar) { - OwningExprResult CondResult(cond.release()); - - VarDecl *ConditionVar = 0; - if (CondVar.get()) { - ConditionVar = CondVar.getAs<VarDecl>(); - CondResult = CheckConditionVariable(ConditionVar); - if (CondResult.isInvalid()) - return StmtError(); - } - SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, - CondResult.takeAs<Expr>()); - getSwitchStack().push_back(SS); - return Owned(SS); -} - /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. @@ -540,14 +518,36 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, return false; } -/// ActOnSwitchBodyError - This is called if there is an error parsing the -/// body of the switch stmt instead of ActOnFinishSwitchStmt. -void Sema::ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, - StmtArg Body) { - // Keep the switch stack balanced. - assert(getSwitchStack().back() == (SwitchStmt*)Switch.get() && - "switch stack missing push/pop!"); - getSwitchStack().pop_back(); +Action::OwningStmtResult +Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ExprArg Cond, + DeclPtrTy CondVar) { + VarDecl *ConditionVar = 0; + if (CondVar.get()) { + ConditionVar = CondVar.getAs<VarDecl>(); + OwningExprResult CondE = CheckConditionVariable(ConditionVar, SourceLocation(), false); + if (CondE.isInvalid()) + return StmtError(); + + Cond = move(CondE); + } + + Expr *CondExpr = Cond.takeAs<Expr>(); + if (!CondExpr) + return StmtError(); + + if (getLangOptions().CPlusPlus && + CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr)) + return StmtError(); + + if (!CondVar.get()) { + CondExpr = MaybeCreateCXXExprWithTemporaries(CondExpr); + if (!CondExpr) + return StmtError(); + } + + SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, CondExpr); + getSwitchStack().push_back(SS); + return Owned(SS); } Action::OwningStmtResult @@ -567,13 +567,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } Expr *CondExpr = SS->getCond(); + Expr *CondExprBeforePromotion = CondExpr; QualType CondTypeBeforePromotion = GetTypeBeforeIntegralPromotion(CondExpr); - if (getLangOptions().CPlusPlus && - CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr)) - return StmtError(); - // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. UsualUnaryConversions(CondExpr); QualType CondType = CondExpr->getType(); @@ -679,16 +676,38 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } if (!HasDependentValue) { + // If we don't have a default statement, check whether the + // condition is constant. + llvm::APSInt ConstantCondValue; + bool HasConstantCond = false; + bool ShouldCheckConstantCond = false; + if (!HasDependentValue && !TheDefaultStmt) { + Expr::EvalResult Result; + HasConstantCond = CondExprBeforePromotion->Evaluate(Result, Context); + if (HasConstantCond) { + assert(Result.Val.isInt() && "switch condition evaluated to non-int"); + ConstantCondValue = Result.Val.getInt(); + ShouldCheckConstantCond = true; + + assert(ConstantCondValue.getBitWidth() == CondWidth && + ConstantCondValue.isSigned() == CondIsSigned); + } + } + // Sort all the scalar case values so we can easily detect duplicates. std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals); if (!CaseVals.empty()) { - for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) { - if (CaseVals[i].first == CaseVals[i+1].first) { + for (unsigned i = 0, e = CaseVals.size(); i != e; ++i) { + if (ShouldCheckConstantCond && + CaseVals[i].first == ConstantCondValue) + ShouldCheckConstantCond = false; + + if (i != 0 && CaseVals[i].first == CaseVals[i-1].first) { // If we have a duplicate, report it. - Diag(CaseVals[i+1].second->getLHS()->getLocStart(), - diag::err_duplicate_case) << CaseVals[i].first.toString(10); Diag(CaseVals[i].second->getLHS()->getLocStart(), + diag::err_duplicate_case) << CaseVals[i].first.toString(10); + Diag(CaseVals[i-1].second->getLHS()->getLocStart(), diag::note_duplicate_case_prev); // FIXME: We really want to remove the bogus case stmt from the // substmt, but we have no way to do this right now. @@ -707,6 +726,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // Scan the ranges, computing the high values and removing empty ranges. std::vector<llvm::APSInt> HiVals; for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { + llvm::APSInt &LoVal = CaseRanges[i].first; CaseStmt *CR = CaseRanges[i].second; Expr *Hi = CR->getRHS(); llvm::APSInt HiVal = Hi->EvaluateAsInt(Context); @@ -722,7 +742,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, CR->setRHS(Hi); // If the low value is bigger than the high value, the case is empty. - if (CaseRanges[i].first > HiVal) { + if (LoVal > HiVal) { Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range) << SourceRange(CR->getLHS()->getLocStart(), CR->getRHS()->getLocEnd()); @@ -730,6 +750,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, --i, --e; continue; } + + if (ShouldCheckConstantCond && + LoVal <= ConstantCondValue && + ConstantCondValue <= HiVal) + ShouldCheckConstantCond = false; + HiVals.push_back(HiVal); } @@ -783,18 +809,32 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } } - // Check to see if switch is over an Enum and handles all of its - // values + // Complain if we have a constant condition and we didn't find a match. + if (!CaseListIsErroneous && ShouldCheckConstantCond) { + // TODO: it would be nice if we printed enums as enums, chars as + // chars, etc. + Diag(CondExpr->getExprLoc(), diag::warn_missing_case_for_condition) + << ConstantCondValue.toString(10) + << CondExpr->getSourceRange(); + } + + // Check to see if switch is over an Enum and handles all of its + // values. We don't need to do this if there's a default + // statement or if we have a constant condition. + // + // TODO: we might want to check whether case values are out of the + // enum even if we don't want to check whether all cases are handled. const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>(); // If switch has default case, then ignore it. - if (!CaseListIsErroneous && !TheDefaultStmt && ET) { + if (!CaseListIsErroneous && !TheDefaultStmt && !HasConstantCond && ET) { const EnumDecl *ED = ET->getDecl(); typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; EnumValsTy EnumVals; - // Gather all enum values, set their type and sort them, allowing easier comparison - // with CaseVals. - for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); EDI != ED->enumerator_end(); EDI++) { + // Gather all enum values, set their type and sort them, + // allowing easier comparison with CaseVals. + for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); + EDI != ED->enumerator_end(); EDI++) { llvm::APSInt Val = (*EDI)->getInitVal(); if(Val.getBitWidth() < CondWidth) Val.extend(CondWidth); @@ -802,30 +842,36 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, EnumVals.push_back(std::make_pair(Val, (*EDI))); } std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); - EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); + EnumValsTy::iterator EIend = + std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); // See which case values aren't in enum EnumValsTy::const_iterator EI = EnumVals.begin(); - for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) { + for (CaseValsTy::const_iterator CI = CaseVals.begin(); + CI != CaseVals.end(); CI++) { while (EI != EIend && EI->first < CI->first) EI++; if (EI == EIend || EI->first > CI->first) - Diag(CI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName(); + Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); } // See which of case ranges aren't in enum EI = EnumVals.begin(); - for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end() && EI != EIend; RI++) { + for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); + RI != CaseRanges.end() && EI != EIend; RI++) { while (EI != EIend && EI->first < RI->first) EI++; if (EI == EIend || EI->first != RI->first) { - Diag(RI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName(); + Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); } llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); while (EI != EIend && EI->first < Hi) EI++; if (EI == EIend || EI->first != Hi) - Diag(RI->second->getRHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName(); + Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); } //Check which enum vals aren't in switch CaseValsTy::const_iterator CI = CaseVals.begin(); @@ -848,7 +894,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } if (RI == CaseRanges.end() || EI->first < RI->first) - Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) << EI->second->getDeclName(); + Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) + << EI->second->getDeclName(); } } } @@ -870,7 +917,7 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, VarDecl *ConditionVar = 0; if (CondVar.get()) { ConditionVar = CondVar.getAs<VarDecl>(); - CondResult = CheckConditionVariable(ConditionVar); + CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true); if (CondResult.isInvalid()) return StmtError(); } @@ -878,11 +925,6 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, if (!ConditionExpr) return StmtError(); - if (CheckBooleanCondition(ConditionExpr, WhileLoc)) { - CondResult = ConditionExpr; - return StmtError(); - } - Stmt *bodyStmt = Body.takeAs<Stmt>(); DiagnoseUnusedExprResult(bodyStmt); @@ -903,6 +945,10 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, return StmtError(); } + condExpr = MaybeCreateCXXExprWithTemporaries(condExpr); + if (!condExpr) + return StmtError(); + Stmt *bodyStmt = Body.takeAs<Stmt>(); DiagnoseUnusedExprResult(bodyStmt); @@ -939,17 +985,11 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, VarDecl *ConditionVar = 0; if (secondVar.get()) { ConditionVar = secondVar.getAs<VarDecl>(); - SecondResult = CheckConditionVariable(ConditionVar); + SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true); if (SecondResult.isInvalid()) return StmtError(); } - Expr *Second = SecondResult.takeAs<Expr>(); - if (Second && CheckBooleanCondition(Second, ForLoc)) { - SecondResult = Second; - return StmtError(); - } - Expr *Third = third.release().takeAs<Expr>(); Stmt *Body = static_cast<Stmt*>(body.get()); @@ -959,7 +999,8 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, first.release(); body.release(); - return Owned(new (Context) ForStmt(First, Second, ConditionVar, Third, Body, + return Owned(new (Context) ForStmt(First, SecondResult.takeAs<Expr>(), + ConditionVar, Third, Body, ForLoc, LParenLoc, RParenLoc)); } @@ -1068,6 +1109,45 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { return Owned(new (Context) BreakStmt(BreakLoc)); } +/// \brief Determine whether a return statement is a candidate for the named +/// return value optimization (C++0x 12.8p34, bullet 1). +/// +/// \param Ctx The context in which the return expression and type occur. +/// +/// \param RetType The return type of the function or block. +/// +/// \param RetExpr The expression being returned from the function or block. +/// +/// \returns The NRVO candidate variable, if the return statement may use the +/// NRVO, or NULL if there is no such candidate. +static const VarDecl *getNRVOCandidate(ASTContext &Ctx, QualType RetType, + Expr *RetExpr) { + QualType ExprType = RetExpr->getType(); + // - in a return statement in a function with ... + // ... a class return type ... + if (!RetType->isRecordType()) + return 0; + // ... the same cv-unqualified type as the function return type ... + if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) + return 0; + // ... the expression is the name of a non-volatile automatic object ... + // We ignore parentheses here. + // FIXME: Is this compliant? (Everyone else does it) + const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens()); + if (!DR) + return 0; + const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); + if (!VD) + return 0; + + if (VD->getKind() == Decl::Var && VD->hasLocalStorage() && + !VD->getType()->isReferenceType() && !VD->hasAttr<BlocksAttr>() && + !VD->getType().isVolatileQualified()) + return VD; + + return 0; +} + /// ActOnBlockReturnStmt - Utility routine to figure out block's return type. /// Action::OwningStmtResult @@ -1102,68 +1182,58 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Otherwise, verify that this result type matches the previous one. We are // pickier with blocks than for normal functions because we don't have GCC // compatibility to worry about here. + ReturnStmt *Result = 0; if (CurBlock->ReturnType->isVoidType()) { if (RetValExp) { Diag(ReturnLoc, diag::err_return_block_has_expr); RetValExp->Destroy(Context); RetValExp = 0; } - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); - } - - if (!RetValExp) + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); + } else if (!RetValExp) { return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + } else { + const VarDecl *NRVOCandidate = 0; + + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + // we have a non-void block with an expression, continue checking + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. + + // In C++ the return statement is handled via a copy initialization. + // the C version of which boils down to CheckSingleAssignmentConstraints. + NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); + OwningExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, + NRVOCandidate != 0), + SourceLocation(), + Owned(RetValExp)); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? + return StmtError(); + } + + if (RetValExp) + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { - // we have a non-void block with an expression, continue checking - - // C99 6.8.6.4p3(136): The return statement is not an assignment. The - // overlap restriction of subclause 6.5.16.1 does not apply to the case of - // function return. - - // In C++ the return statement is handled via a copy initialization. - // the C version of which boils down to CheckSingleAssignmentConstraints. - OwningExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeResult(ReturnLoc, - FnRetType), - SourceLocation(), - Owned(RetValExp)); - if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? - return StmtError(); + RetValExp = Res.takeAs<Expr>(); + if (RetValExp) + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - RetValExp = Res.takeAs<Expr>(); - if (RetValExp) - CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); -} - -/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that -/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15). -static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType, - Expr *RetExpr) { - QualType ExprType = RetExpr->getType(); - // - in a return statement in a function with ... - // ... a class return type ... - if (!RetType->isRecordType()) - return false; - // ... the same cv-unqualified type as the function return type ... - if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) - return false; - // ... the expression is the name of a non-volatile automatic object ... - // We ignore parentheses here. - // FIXME: Is this compliant? - const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens()); - if (!DR) - return false; - const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); - if (!VD) - return false; - return VD->hasLocalStorage() && !VD->getType()->isReferenceType() - && !VD->getType().isVolatileQualified(); + // If we need to check for the named return value optimization, save the + // return statement in our scope for later processing. + if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && + !CurContext->isDependentContext()) + FunctionScopes.back()->Returns.push_back(Result); + + return Owned(Result); } Action::OwningStmtResult @@ -1184,6 +1254,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { else // If we don't have a function/method context, bail. return StmtError(); + ReturnStmt *Result = 0; if (FnRetType->isVoidType()) { if (RetValExp && !RetValExp->isTypeDependent()) { // C99 6.8.6.4p1 (ext_ since GCC warns) @@ -1202,10 +1273,9 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); } - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); - } - - if (!RetValExp && !FnRetType->isDependentType()) { + + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); + } else if (!RetValExp && !FnRetType->isDependentType()) { unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4 // C99 6.8.6.4p1 (ext_ since GCC warns) if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr; @@ -1214,54 +1284,47 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/; else Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/; - return Owned(new (Context) ReturnStmt(ReturnLoc, (Expr*)0)); - } + Result = new (Context) ReturnStmt(ReturnLoc); + } else { + const VarDecl *NRVOCandidate = 0; + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + // we have a non-void function with an expression, continue checking + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. + + // In C++ the return statement is handled via a copy initialization. + // the C version of which boils down to CheckSingleAssignmentConstraints. + NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); + OwningExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, + NRVOCandidate != 0), + SourceLocation(), + Owned(RetValExp)); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? + return StmtError(); + } - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { - // we have a non-void function with an expression, continue checking - - // C99 6.8.6.4p3(136): The return statement is not an assignment. The - // overlap restriction of subclause 6.5.16.1 does not apply to the case of - // function return. - - // C++0x 12.8p15: When certain criteria are met, an implementation is - // allowed to omit the copy construction of a class object, [...] - // - in a return statement in a function with a class return type, when - // the expression is the name of a non-volatile automatic object with - // the same cv-unqualified type as the function return type, the copy - // operation can be omitted [...] - // C++0x 12.8p16: When the criteria for elision of a copy operation are met - // and the object to be copied is designated by an lvalue, overload - // resolution to select the constructor for the copy is first performed - // as if the object were designated by an rvalue. - // Note that we only compute Elidable if we're in C++0x, since we don't - // care otherwise. - bool Elidable = getLangOptions().CPlusPlus0x ? - IsReturnCopyElidable(Context, FnRetType, RetValExp) : - false; - // FIXME: Elidable - (void)Elidable; - - // In C++ the return statement is handled via a copy initialization. - // the C version of which boils down to CheckSingleAssignmentConstraints. - OwningExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeResult(ReturnLoc, - FnRetType), - SourceLocation(), - Owned(RetValExp)); - if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? - return StmtError(); + RetValExp = Res.takeAs<Expr>(); + if (RetValExp) + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - - RetValExp = Res.takeAs<Expr>(); - if (RetValExp) - CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + + if (RetValExp) + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - - if (RetValExp) - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); + + // If we need to check for the named return value optimization, save the + // return statement in our scope for later processing. + if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && + !CurContext->isDependentContext()) + FunctionScopes.back()->Returns.push_back(Result); + + return Owned(Result); } /// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 694b21c8393f..307be9d78658 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -100,10 +100,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S, UnqualifiedId &Name, TypeTy *ObjectTypePtr, bool EnteringContext, - TemplateTy &TemplateResult) { + TemplateTy &TemplateResult, + bool &MemberOfUnknownSpecialization) { assert(getLangOptions().CPlusPlus && "No template names in C!"); DeclarationName TName; + MemberOfUnknownSpecialization = false; switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: @@ -128,7 +130,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, LookupResult R(*this, TName, Name.getSourceRange().getBegin(), LookupOrdinaryName); R.suppressDiagnostics(); - LookupTemplateName(R, S, SS, ObjectType, EnteringContext); + LookupTemplateName(R, S, SS, ObjectType, EnteringContext, + MemberOfUnknownSpecialization); if (R.empty() || R.isAmbiguous()) return TNK_Non_template; @@ -172,6 +175,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, TemplateNameKind &SuggestedKind) { // We can't recover unless there's a dependent scope specifier preceding the // template name. + // FIXME: Typo correction? if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) || computeDeclContext(*SS)) return false; @@ -191,8 +195,10 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, void Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, - bool EnteringContext) { + bool EnteringContext, + bool &MemberOfUnknownSpecialization) { // Determine where to perform name lookup + MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = 0; bool isDependent = false; if (!ObjectType.isNull()) { @@ -241,6 +247,7 @@ void Sema::LookupTemplateName(LookupResult &Found, } else if (isDependent) { // We cannot look into a dependent object type or nested nme // specifier. + MemberOfUnknownSpecialization = true; return; } else { // Perform unqualified name lookup in the current scope. @@ -330,11 +337,13 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, const TemplateArgumentListInfo *TemplateArgs) { NestedNameSpecifier *Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + + DeclContext *DC = getFunctionLevelDeclContext(); if (!isAddressOfOperand && - isa<CXXMethodDecl>(CurContext) && - cast<CXXMethodDecl>(CurContext)->isInstance()) { - QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); + isa<CXXMethodDecl>(DC) && + cast<CXXMethodDecl>(DC)->isInstance()) { + QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. @@ -525,6 +534,14 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, /// otherwise, produces a diagnostic and returns a NULL type. QualType Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { + // We don't allow variably-modified types as the type of non-type template + // parameters. + if (T->isVariablyModifiedType()) { + Diag(Loc, diag::err_variably_modified_nontype_template_param) + << T; + return QualType(); + } + // C++ [temp.param]p4: // // A non-type template-parameter shall have one of the following @@ -555,7 +572,7 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { else if (T->isFunctionType()) // FIXME: Keep the type prior to promotion? return Context.getPointerType(T); - + Diag(Loc, diag::err_template_nontype_parm_bad_type) << T; @@ -739,8 +756,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (CheckTemplateDeclScope(S, TemplateParams)) return true; - TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec); - assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type"); + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); + assert(Kind != TTK_Enum && "can't build template of enumerated type"); // There is no such thing as an unnamed class template. if (!Name) { @@ -1088,7 +1105,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, DiagnoseDefaultTemplateArgument(*this, TPC, NewTypeParm->getLocation(), NewTypeParm->getDefaultArgumentInfo()->getTypeLoc() - .getFullSourceRange())) + .getSourceRange())) NewTypeParm->removeDefaultArgument(); // Merge default arguments for template type parameters. @@ -1506,10 +1523,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // specialization. Create the canonical declaration and add it to // the set of specializations. Decl = ClassTemplateSpecializationDecl::Create(Context, - ClassTemplate->getDeclContext(), - ClassTemplate->getLocation(), - ClassTemplate, - Converted, 0); + ClassTemplate->getTemplatedDecl()->getTagKind(), + ClassTemplate->getDeclContext(), + ClassTemplate->getLocation(), + ClassTemplate, + Converted, 0); ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos); Decl->setLexicalDeclContext(CurContext); } @@ -1567,7 +1585,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, QualType Type = GetTypeFromParser(TypeResult.get(), &DI); // Verify the tag specifier. - TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); + TagTypeKind TagKind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); if (const RecordType *RT = Type->getAs<RecordType>()) { RecordDecl *D = RT->getDecl(); @@ -1583,7 +1601,9 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, } } - QualType ElabType = Context.getElaboratedType(Type, TagKind); + ElaboratedTypeKeyword Keyword + = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); + QualType ElabType = Context.getElaboratedType(Keyword, /*NNS=*/0, Type); return ElabType.getAsOpaquePtr(); } @@ -1618,8 +1638,8 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(), Qualifier, QualifierRange, R.getLookupName(), R.getNameLoc(), - RequiresADL, TemplateArgs); - ULE->addDecls(R.begin(), R.end()); + RequiresADL, TemplateArgs, + R.begin(), R.end()); return Owned(ULE); } @@ -1636,8 +1656,10 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, RequireCompleteDeclContext(SS, DC)) return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs); + bool MemberOfUnknownSpecialization; LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); - LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false); + LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false, + MemberOfUnknownSpecialization); if (R.isAmbiguous()) return ExprError(); @@ -1694,8 +1716,10 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, // "template" keyword is now permitted). We follow the C++0x // rules, even in C++03 mode, retroactively applying the DR. TemplateTy Template; + bool MemberOfUnknownSpecialization; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, - EnteringContext, Template); + EnteringContext, Template, + MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && LookupCtx->isDependentContext() && isa<CXXRecordDecl>(LookupCtx) && cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) { @@ -1704,7 +1728,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name) - << Name.getSourceRange(); + << Name.getSourceRange() + << TemplateKWLoc; return TemplateTy(); } else { // We found something; return it. @@ -1734,7 +1759,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name) - << Name.getSourceRange(); + << Name.getSourceRange() + << TemplateKWLoc; return TemplateTy(); } @@ -2336,24 +2362,27 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, // compounded from any of these types shall not be used as a // template-argument for a template type-parameter. // - // FIXME: Perform the recursive and no-linkage type checks. + // FIXME: Perform the unnamed type check. + SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); const TagType *Tag = 0; if (const EnumType *EnumT = Arg->getAs<EnumType>()) Tag = EnumT; else if (const RecordType *RecordT = Arg->getAs<RecordType>()) Tag = RecordT; if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) { - SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); + SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); return Diag(SR.getBegin(), diag::err_template_arg_local_type) << QualType(Tag, 0) << SR; } else if (Tag && !Tag->getDecl()->getDeclName() && !Tag->getDecl()->getTypedefForAnonDecl()) { - SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR; Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here); return true; + } else if (Arg->isVariablyModifiedType()) { + Diag(SR.getBegin(), diag::err_variably_modified_template_arg) + << Arg; + return true; } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) { - SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR; } @@ -3661,13 +3690,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Check that the specialization uses the same tag kind as the // original template. - TagDecl::TagKind Kind; - switch (TagSpec) { - default: assert(0 && "Unknown tag type!"); - case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; - case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; - case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; - } + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); + assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, KWLoc, *ClassTemplate->getIdentifier())) { @@ -3796,7 +3820,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber() : ClassTemplate->getPartialSpecializations().size(); ClassTemplatePartialSpecializationDecl *Partial - = ClassTemplatePartialSpecializationDecl::Create(Context, + = ClassTemplatePartialSpecializationDecl::Create(Context, Kind, ClassTemplate->getDeclContext(), TemplateNameLoc, TemplateParams, @@ -3857,7 +3881,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. Specialization - = ClassTemplateSpecializationDecl::Create(Context, + = ClassTemplateSpecializationDecl::Create(Context, Kind, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, @@ -4217,10 +4241,10 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, return false; } -/// \brief Perform semantic analysis for the given function template +/// \brief Perform semantic analysis for the given function template /// specialization. /// -/// This routine performs all of the semantic analysis required for an +/// This routine performs all of the semantic analysis required for an /// explicit function template specialization. On successful completion, /// the function declaration \p FD will become a function template /// specialization. @@ -4228,24 +4252,14 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, /// \param FD the function declaration, which will be updated to become a /// function template specialization. /// -/// \param HasExplicitTemplateArgs whether any template arguments were -/// explicitly provided. -/// -/// \param LAngleLoc the location of the left angle bracket ('<'), if -/// template arguments were explicitly provided. -/// -/// \param ExplicitTemplateArgs the explicitly-provided template arguments, -/// if any. -/// -/// \param NumExplicitTemplateArgs the number of explicitly-provided template -/// arguments. This number may be zero even when HasExplicitTemplateArgs is -/// true as in, e.g., \c void sort<>(char*, char*); +/// \param ExplicitTemplateArgs the explicitly-provided template arguments, +/// if any. Note that this may be valid info even when 0 arguments are +/// explicitly provided as in, e.g., \c void sort<>(char*, char*); +/// as it anyway contains info on the angle brackets locations. /// -/// \param RAngleLoc the location of the right angle bracket ('>'), if -/// template arguments were explicitly provided. -/// -/// \param PrevDecl the set of declarations that -bool +/// \param PrevDecl the set of declarations that may be specialized by +/// this function specialization. +bool Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous) { @@ -4347,12 +4361,16 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Turn the given function declaration into a function template // specialization, with the template arguments from the previous // specialization. + // Take copies of (semantic and syntactic) template argument lists. + const TemplateArgumentList* TemplArgs = new (Context) + TemplateArgumentList(Specialization->getTemplateSpecializationArgs()); + const TemplateArgumentListInfo* TemplArgsAsWritten = ExplicitTemplateArgs + ? new (Context) TemplateArgumentListInfo(*ExplicitTemplateArgs) : 0; FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(), - new (Context) TemplateArgumentList( - *Specialization->getTemplateSpecializationArgs()), - /*InsertPos=*/0, - SpecInfo->getTemplateSpecializationKind()); - + TemplArgs, /*InsertPos=*/0, + SpecInfo->getTemplateSpecializationKind(), + TemplArgsAsWritten); + // The "previous declaration" for this function template specialization is // the prior function template specialization. Previous.clear(); @@ -4541,10 +4559,16 @@ static void CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, if (S.getLangOptions().CPlusPlus0x && !CurContext->Encloses(ExpectedContext)) { if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ExpectedContext)) - S.Diag(InstLoc, diag::err_explicit_instantiation_out_of_scope) + S.Diag(InstLoc, + S.getLangOptions().CPlusPlus0x? + diag::err_explicit_instantiation_out_of_scope + : diag::warn_explicit_instantiation_out_of_scope_0x) << D << NS; else - S.Diag(InstLoc, diag::err_explicit_instantiation_must_be_global) + S.Diag(InstLoc, + S.getLangOptions().CPlusPlus0x? + diag::err_explicit_instantiation_must_be_global + : diag::warn_explicit_instantiation_out_of_scope_0x) << D; S.Diag(D->getLocation(), diag::note_explicit_instantiation_here); return; @@ -4561,7 +4585,10 @@ static void CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, if (CurContext->Equals(ExpectedContext)) return; - S.Diag(InstLoc, diag::err_explicit_instantiation_unqualified_wrong_namespace) + S.Diag(InstLoc, + S.getLangOptions().CPlusPlus0x? + diag::err_explicit_instantiation_unqualified_wrong_namespace + : diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x) << D << ExpectedContext; S.Diag(D->getLocation(), diag::note_explicit_instantiation_here); } @@ -4588,7 +4615,6 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { } // Explicit instantiation of a class template specialization -// FIXME: Implement extern template semantics Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, @@ -4609,13 +4635,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Check that the specialization uses the same tag kind as the // original template. - TagDecl::TagKind Kind; - switch (TagSpec) { - default: assert(0 && "Unknown tag type!"); - case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; - case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; - case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; - } + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); + assert(Kind != TTK_Enum && + "Invalid enum tag in class template explicit instantiation!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, KWLoc, *ClassTemplate->getIdentifier())) { @@ -4703,7 +4725,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Create a new class template specialization declaration node for // this explicit specialization. Specialization - = ClassTemplateSpecializationDecl::Create(Context, + = ClassTemplateSpecializationDecl::Create(Context, Kind, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, @@ -4755,7 +4777,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->getDefinition()); if (!Def) InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK); - + else if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(TemplateNameLoc, Specialization, true); + // Instantiate the members of this class template specialization. Def = cast_or_null<ClassTemplateSpecializationDecl>( Specialization->getDefinition()); @@ -4890,6 +4914,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, InstantiateClassMembers(NameLoc, RecordDef, getTemplateInstantiationArgs(Record), TSK); + if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(NameLoc, RecordDef, true); + // FIXME: We don't have any representation for explicit instantiations of // member classes. Such a representation is not needed for compilation, but it // should be available for clients that want to see all of the declarations in @@ -5161,37 +5188,33 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (!NNS) return true; - ElaboratedTypeKeyword Keyword = ETK_None; - switch (TagDecl::getTagKindForTypeSpec(TagSpec)) { - case TagDecl::TK_struct: Keyword = ETK_Struct; break; - case TagDecl::TK_class: Keyword = ETK_Class; break; - case TagDecl::TK_union: Keyword = ETK_Union; break; - case TagDecl::TK_enum: Keyword = ETK_Enum; break; - } - assert(Keyword != ETK_None && "Invalid tag kind!"); + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); if (TUK == TUK_Declaration || TUK == TUK_Definition) { Diag(NameLoc, diag::err_dependent_tag_decl) - << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec) - << SS.getRange(); + << (TUK == TUK_Definition) << Kind << SS.getRange(); return true; } - - return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr(); + + ElaboratedTypeKeyword Kwd = TypeWithKeyword::getKeywordForTagTypeKind(Kind); + return Context.getDependentNameType(Kwd, NNS, Name).getAsOpaquePtr(); } static void FillTypeLoc(DependentNameTypeLoc TL, SourceLocation TypenameLoc, - SourceRange QualifierRange) { - // FIXME: typename, qualifier range - TL.setNameLoc(TypenameLoc); + SourceRange QualifierRange, + SourceLocation NameLoc) { + TL.setKeywordLoc(TypenameLoc); + TL.setQualifierRange(QualifierRange); + TL.setNameLoc(NameLoc); } -static void FillTypeLoc(QualifiedNameTypeLoc TL, +static void FillTypeLoc(ElaboratedTypeLoc TL, SourceLocation TypenameLoc, SourceRange QualifierRange) { - // FIXME: typename, qualifier range - TL.setNameLoc(TypenameLoc); + // FIXME: inner locations. + TL.setKeywordLoc(TypenameLoc); + TL.setQualifierRange(QualifierRange); } Sema::TypeResult @@ -5203,7 +5226,7 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, return true; QualType T = CheckTypenameType(ETK_Typename, NNS, II, - SourceRange(TypenameLoc, IdLoc)); + TypenameLoc, SS.getRange(), IdLoc); if (T.isNull()) return true; @@ -5211,9 +5234,9 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, if (isa<DependentNameType>(T)) { DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); // FIXME: fill inner type loc - FillTypeLoc(TL, TypenameLoc, SS.getRange()); + FillTypeLoc(TL, TypenameLoc, SS.getRange(), IdLoc); } else { - QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc()); // FIXME: fill inner type loc FillTypeLoc(TL, TypenameLoc, SS.getRange()); } @@ -5233,14 +5256,11 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, if (computeDeclContext(SS, false)) { // If we can compute a declaration context, then the "typename" - // keyword was superfluous. Just build a QualifiedNameType to keep + // keyword was superfluous. Just build an ElaboratedType to keep // track of the nested-name-specifier. - - // FIXME: Note that the QualifiedNameType had the "typename" keyword! - - T = Context.getQualifiedNameType(NNS, T); + T = Context.getElaboratedType(ETK_Typename, NNS, T); TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); - QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc()); // FIXME: fill inner type loc FillTypeLoc(TL, TypenameLoc, SS.getRange()); return CreateLocInfoType(T, TSI).getAsOpaquePtr(); @@ -5250,7 +5270,7 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); // FIXME: fill inner type loc - FillTypeLoc(TL, TypenameLoc, SS.getRange()); + FillTypeLoc(TL, TypenameLoc, SS.getRange(), TemplateLoc); return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } @@ -5259,10 +5279,11 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, QualType Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo &II, - SourceRange Range) { + SourceLocation KeywordLoc, SourceRange NNSRange, + SourceLocation IILoc) { CXXScopeSpec SS; SS.setScopeRep(NNS); - SS.setRange(Range); + SS.setRange(NNSRange); DeclContext *Ctx = computeDeclContext(SS); if (!Ctx) { @@ -5282,7 +5303,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, return QualType(); DeclarationName Name(&II); - LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName); + LookupResult Result(*this, Name, IILoc, LookupOrdinaryName); LookupQualifiedName(Result, Ctx); unsigned DiagID = 0; Decl *Referenced = 0; @@ -5297,10 +5318,10 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { - // We found a type. Build a QualifiedNameType, since the - // typename-specifier was just sugar. FIXME: Tell - // QualifiedNameType that it has a "typename" prefix. - return Context.getQualifiedNameType(NNS, Context.getTypeDeclType(Type)); + // We found a type. Build an ElaboratedType, since the + // typename-specifier was just sugar. + return Context.getElaboratedType(ETK_Typename, NNS, + Context.getTypeDeclType(Type)); } DiagID = diag::err_typename_nested_not_type; @@ -5322,7 +5343,9 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // If we get here, it's because name lookup did not find a // type. Emit an appropriate diagnostic and return an error. - Diag(Range.getEnd(), DiagID) << Range << Name << Ctx; + SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(), + IILoc); + Diag(IILoc, DiagID) << FullRange << Name << Ctx; if (Referenced) Diag(Referenced->getLocation(), diag::note_typename_refers_here) << Name; @@ -5379,9 +5402,10 @@ namespace { /// \brief Transforms a typename type by determining whether the type now /// refers to a member of the current instantiation, and then - /// type-checking and building a QualifiedNameType (when possible). - QualType TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL, - QualType ObjectType); + /// type-checking and building an ElaboratedType (when possible). + QualType TransformDependentNameType(TypeLocBuilder &TLB, + DependentNameTypeLoc TL, + QualType ObjectType); }; } @@ -5393,7 +5417,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), - /*FIXME:*/SourceRange(getBaseLocation()), + TL.getQualifierRange(), ObjectType); if (!NNS) return QualType(); @@ -5402,7 +5426,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, // context corresponding to the nested-name-specifier, then this // typename type will not change; exit early. CXXScopeSpec SS; - SS.setRange(SourceRange(getBaseLocation())); + SS.setRange(TL.getQualifierRange()); SS.setScopeRep(NNS); QualType Result; @@ -5410,7 +5434,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, Result = QualType(T, 0); // Rebuild the typename type, which will probably turn into a - // QualifiedNameType. + // ElaboratedType. else if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { QualType NewTemplateId = TransformType(QualType(TemplateId, 0)); @@ -5421,18 +5445,38 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, NewTemplateId == QualType(TemplateId, 0)) Result = QualType(T, 0); else - Result = getDerived().RebuildDependentNameType(T->getKeyword(), + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, NewTemplateId); } else - Result = getDerived().RebuildDependentNameType(T->getKeyword(), - NNS, T->getIdentifier(), - SourceRange(TL.getNameLoc())); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + T->getIdentifier(), + TL.getKeywordLoc(), + TL.getQualifierRange(), + TL.getNameLoc()); if (Result.isNull()) return QualType(); - DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); + if (const ElaboratedType* ElabT = Result->getAs<ElaboratedType>()) { + QualType NamedT = ElabT->getNamedType(); + if (isa<TemplateSpecializationType>(NamedT)) { + TemplateSpecializationTypeLoc NamedTLoc + = TLB.push<TemplateSpecializationTypeLoc>(NamedT); + // FIXME: fill locations + NamedTLoc.initializeLocal(TL.getNameLoc()); + } else { + TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc()); + } + ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); + } + else { + DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); + NewTL.setNameLoc(TL.getNameLoc()); + } return Result; } @@ -5459,7 +5503,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, /// Here, the type "typename X<T>::pointer" will be created as a DependentNameType, /// since we do not know that we can look into X<T> when we parsed the type. /// This function will rebuild the type, performing the lookup of "pointer" -/// in X<T> and returning a QualifiedNameType whose canonical type is the same +/// in X<T> and returning an ElaboratedType whose canonical type is the same /// as the canonical type of T*, allowing the return types of the out-of-line /// definition and the declaration to match. TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 2bb97eba11cb..88ceeca58a66 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -482,14 +482,20 @@ DeduceTemplateArguments(Sema &S, // T * case Type::Pointer: { - const PointerType *PointerArg = Arg->getAs<PointerType>(); - if (!PointerArg) + QualType PointeeType; + if (const PointerType *PointerArg = Arg->getAs<PointerType>()) { + PointeeType = PointerArg->getPointeeType(); + } else if (const ObjCObjectPointerType *PointerArg + = Arg->getAs<ObjCObjectPointerType>()) { + PointeeType = PointerArg->getPointeeType(); + } else { return Sema::TDK_NonDeducedMismatch; + } unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass); return DeduceTemplateArguments(S, TemplateParams, cast<PointerType>(Param)->getPointeeType(), - PointerArg->getPointeeType(), + PointeeType, Info, Deduced, SubTDF); } @@ -1030,10 +1036,8 @@ FinishTemplateArgumentDeduction(Sema &S, ClassTemplate->getTemplateParameters(), N); if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), - InstArgs, false, ConvertedInstArgs)) { - // FIXME: fail with more useful information? + InstArgs, false, ConvertedInstArgs)) return Sema::TDK_SubstitutionFailure; - } for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) { TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I]; @@ -1190,8 +1194,13 @@ Sema::SubstituteExplicitTemplateArguments( SourceLocation(), ExplicitTemplateArgs, true, - Builder) || Trap.hasErrorOccurred()) + Builder) || Trap.hasErrorOccurred()) { + unsigned Index = Builder.structuredSize(); + if (Index >= TemplateParams->size()) + Index = TemplateParams->size() - 1; + Info.Param = makeTemplateParameter(TemplateParams->getParam(Index)); return TDK_InvalidExplicitArguments; + } // Form the template argument list from the explicitly-specified // template arguments. @@ -1374,6 +1383,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, NTTP->getDeclName()); if (NTTPType.isNull()) { Info.Param = makeTemplateParameter(Param); + Info.reset(new (Context) TemplateArgumentList(Context, Builder, + /*TakeArgs=*/true)); return TDK_SubstitutionFailure; } } @@ -1399,6 +1410,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, : CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); + Info.reset(new (Context) TemplateArgumentList(Context, Builder, + /*TakeArgs=*/true)); return TDK_SubstitutionFailure; } @@ -1429,6 +1442,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); + Info.reset(new (Context) TemplateArgumentList(Context, Builder, + /*TakeArgs=*/true)); return TDK_SubstitutionFailure; } @@ -1456,7 +1471,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // If the template argument list is owned by the function template // specialization, release it. - if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList) + if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList && + !Trap.hasErrorOccurred()) Info.take(); // There may have been an error that did not prevent us from constructing a @@ -2636,6 +2652,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, case Type::Record: case Type::Enum: case Type::ObjCInterface: + case Type::ObjCObject: case Type::ObjCObjectPointer: case Type::UnresolvedUsing: #define TYPE(Class, Base) diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 14bd24320104..1adf594c1eff 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -560,9 +560,7 @@ namespace { /// /// For the purposes of template instantiation, a type has already been /// transformed if it is NULL or if it is not dependent. - bool AlreadyTransformed(QualType T) { - return T.isNull() || !T->isDependentType(); - } + bool AlreadyTransformed(QualType T); /// \brief Returns the location of the entity being instantiated, if known. SourceLocation getBaseLocation() { return Loc; } @@ -603,7 +601,8 @@ namespace { /// \brief Check for tag mismatches when instantiating an /// elaborated type. - QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); + QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, QualType T); Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); @@ -624,6 +623,17 @@ namespace { }; } +bool TemplateInstantiator::AlreadyTransformed(QualType T) { + if (T.isNull()) + return true; + + if (T->isDependentType() || T->isVariablyModifiedType()) + return false; + + getSema().MarkDeclarationsReferencedInType(Loc, T); + return true; +} + Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { if (!D) return 0; @@ -710,8 +720,9 @@ VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, } QualType -TemplateInstantiator::RebuildElaboratedType(QualType T, - ElaboratedType::TagKind Tag) { +TemplateInstantiator::RebuildElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + QualType T) { if (const TagType *TT = T->getAs<TagType>()) { TagDecl* TD = TT->getDecl(); @@ -723,16 +734,20 @@ TemplateInstantiator::RebuildElaboratedType(QualType T, // TODO: should we even warn on struct/class mismatches for this? Seems // like it's likely to produce a lot of spurious errors. - if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) { - SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) - << Id - << FixItHint::CreateReplacement(SourceRange(TagLocation), - TD->getKindName()); - SemaRef.Diag(TD->getLocation(), diag::note_previous_use); + if (Keyword != ETK_None && Keyword != ETK_Typename) { + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); + if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) { + SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) + << Id + << FixItHint::CreateReplacement(SourceRange(TagLocation), + TD->getKindName()); + SemaRef.Diag(TD->getLocation(), diag::note_previous_use); + } } } - return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag); + return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(Keyword, + NNS, T); } Sema::OwningExprResult @@ -927,7 +942,8 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T, "Cannot perform an instantiation without some context on the " "instantiation stack"); - if (!T->getType()->isDependentType()) + if (!T->getType()->isDependentType() && + !T->getType()->isVariablyModifiedType()) return T; TemplateInstantiator Instantiator(*this, Args, Loc, Entity); @@ -942,8 +958,9 @@ QualType Sema::SubstType(QualType T, "Cannot perform an instantiation without some context on the " "instantiation stack"); - // If T is not a dependent type, there is nothing to do. - if (!T->isDependentType()) + // If T is not a dependent type or a variably-modified type, there + // is nothing to do. + if (!T->isDependentType() && !T->isVariablyModifiedType()) return T; TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); @@ -951,7 +968,7 @@ QualType Sema::SubstType(QualType T, } static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { - if (T->getType()->isDependentType()) + if (T->getType()->isDependentType() || T->getType()->isVariablyModifiedType()) return true; TypeLoc TL = T->getTypeLoc(); @@ -1160,6 +1177,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. ContextRAII SavedContext(*this, Instantiation); + EnterExpressionEvaluationContext EvalContext(*this, + Action::PotentiallyEvaluated); // If this is an instantiation of a local class, merge this local // instantiation scope with the enclosing scope. Otherwise, every @@ -1169,6 +1188,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Start the definition of this instantiation. Instantiation->startDefinition(); + + Instantiation->setTagKind(Pattern->getTagKind()); // Do substitution on the base class specifiers. if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) @@ -1202,25 +1223,15 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Exit the scope of this instantiation. SavedContext.pop(); - // If this is a polymorphic C++ class without a key function, we'll - // have to mark all of the virtual members to allow emission of a vtable - // in this translation unit. - if (Instantiation->isDynamicClass() && - !Context.getKeyFunction(Instantiation)) { - // Local classes need to have their methods instantiated immediately in - // order to have the correct instantiation scope. - if (Instantiation->isLocalClass()) { - MarkVirtualMembersReferenced(PointOfInstantiation, - Instantiation); - } else { - ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation, - PointOfInstantiation)); - } - } - - if (!Invalid) + if (!Invalid) { Consumer.HandleTagDeclDefinition(Instantiation); + // Always emit the vtable for an explicit instantiation definition + // of a polymorphic class template specialization. + if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(PointOfInstantiation, Instantiation, true); + } + return Invalid; } @@ -1244,6 +1255,12 @@ Sema::InstantiateClassTemplateSpecialization( // declaration (C++0x [temp.explicit]p10); go ahead and perform the // explicit instantiation. ClassTemplateSpec->setSpecializationKind(TSK); + + // If this is an explicit instantiation definition, mark the + // vtable as used. + if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(PointOfInstantiation, ClassTemplateSpec, true); + return false; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index da8480633d5b..834b86da9a0f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -184,13 +184,16 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); - if (DI->getType()->isDependentType()) { + if (DI->getType()->isDependentType() || + DI->getType()->isVariablyModifiedType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) { Invalid = true; DI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy); } + } else { + SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); } // Create the new typedef @@ -215,6 +218,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); } + InstantiateAttrs(D, Typedef); Typedef->setAccess(D->getAccess()); Owner->addDecl(Typedef); @@ -320,6 +324,13 @@ static bool InstantiateInitializer(Sema &S, Expr *Init, } Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { + // If this is the variable for an anonymous struct or union, + // instantiate the anonymous struct/union type first. + if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) + if (RecordTy->getDecl()->isAnonymousStructOrUnion()) + if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl()))) + return 0; + // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, @@ -349,7 +360,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Var->setLexicalDeclContext(D->getLexicalDeclContext()); Var->setAccess(D->getAccess()); - + Var->setUsed(D->isUsed()); + // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. bool Redeclaration = false; @@ -417,13 +429,18 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { } else if (!Var->isStaticDataMember() || Var->isOutOfLine()) SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); + // Diagnose unused local variables. + if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed()) + SemaRef.DiagnoseUnusedDecl(Var); + return Var; } Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); - if (DI->getType()->isDependentType()) { + if (DI->getType()->isDependentType() || + DI->getType()->isVariablyModifiedType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) { @@ -440,6 +457,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { << DI->getType(); Invalid = true; } + } else { + SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); } Expr *BitWidth = D->getBitWidth(); @@ -480,6 +499,11 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { if (!Field->getDeclName()) { // Keep track of where this decl came from. SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D); + } + if (CXXRecordDecl *Parent= dyn_cast<CXXRecordDecl>(Field->getDeclContext())) { + if (Parent->isAnonymousStructOrUnion() && + Parent->getLookupContext()->isFunctionOrMethod()) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Field); } Field->setImplicit(D->isImplicit()); @@ -903,7 +927,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { if (Decl::FriendObjectKind FOK = D->getFriendObjectKind()) Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared); - Record->setAnonymousStructOrUnion(D->isAnonymousStructOrUnion()); + // Make sure that anonymous structs and unions are recorded. + if (D->isAnonymousStructOrUnion()) { + Record->setAnonymousStructOrUnion(true); + if (Record->getDeclContext()->getLookupContext()->isFunctionOrMethod()) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record); + } Owner->addDecl(Record); return Record; @@ -943,6 +972,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, isFriend = (D->getFriendObjectKind() != Decl::FOK_None); bool MergeWithParentScope = (TemplateParams != 0) || + Owner->isFunctionOrMethod() || !(isa<Decl>(Owner) && cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); @@ -1000,6 +1030,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Params[P]->setOwningFunction(Function); Function->setParams(Params.data(), Params.size()); + SourceLocation InstantiateAtPOI; if (TemplateParams) { // Our resulting instantiation is actually a function template, since we // are substituting only the outer template parameters. For example, given @@ -1118,6 +1149,38 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0); DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false); + + if (!SemaRef.getLangOptions().CPlusPlus0x && + D->isThisDeclarationADefinition()) { + // Check for a function body. + const FunctionDecl *Definition = 0; + if (Function->getBody(Definition) && + Definition->getTemplateSpecializationKind() == TSK_Undeclared) { + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + << Function->getDeclName(); + SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition); + Function->setInvalidDecl(); + } + // Check for redefinitions due to other instantiations of this or + // a similar friend function. + else for (FunctionDecl::redecl_iterator R = Function->redecls_begin(), + REnd = Function->redecls_end(); + R != REnd; ++R) { + if (*R != Function && + ((*R)->getFriendObjectKind() != Decl::FOK_None)) { + if (const FunctionDecl *RPattern + = (*R)->getTemplateInstantiationPattern()) + if (RPattern->getBody(RPattern)) { + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + << Function->getDeclName(); + SemaRef.Diag((*R)->getLocation(), diag::note_previous_definition); + Function->setInvalidDecl(); + break; + } + } + } + } + } if (Function->isOverloadedOperator() && !DC->isRecord() && @@ -1761,7 +1824,9 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // Create the class template partial specialization declaration. ClassTemplatePartialSpecializationDecl *InstPartialSpec - = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, Owner, + = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, + PartialSpec->getTagKind(), + Owner, PartialSpec->getLocation(), InstParams, ClassTemplate, @@ -1946,15 +2011,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive, bool DefinitionRequired) { - if (Function->isInvalidDecl()) + if (Function->isInvalidDecl() || Function->getBody()) return; - assert(!Function->getBody() && "Already instantiated!"); - // Never instantiate an explicit specialization. if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) return; - + // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); Stmt *Pattern = 0; @@ -1975,6 +2038,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl) Diag(PatternDecl->getLocation(), diag::note_explicit_instantiation_here); + Function->setInvalidDecl(); } return; @@ -2000,6 +2064,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Recursive) PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); + EnterExpressionEvaluationContext EvalContext(*this, + Action::PotentiallyEvaluated); ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function)); // Introduce a new scope where local variable instantiations will be @@ -2644,8 +2710,7 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) { Context.getSourceManager(), "instantiating function definition"); - if (!Function->getBody()) - InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true); + InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true); continue; } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index d1a74beb538f..35efa6113b64 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -25,6 +25,8 @@ #include "llvm/Support/ErrorHandling.h" using namespace clang; +#include <iostream> + /// \brief Perform adjustment on the parameter type of a function. /// /// This routine adjusts the given parameter type @p T to the actual @@ -162,9 +164,10 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, + (ObjCProtocolDecl**)PQ, + DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectPointerType(Result); break; } @@ -283,12 +286,11 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // In C++, make an ElaboratedType. if (TheSema.getLangOptions().CPlusPlus) { - TagDecl::TagKind Tag - = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType()); - Result = TheSema.getQualifiedNameType(DS.getTypeSpecScope(), Result); - Result = Context.getElaboratedType(Result, Tag); + ElaboratedTypeKeyword Keyword + = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); + Result = TheSema.getElaboratedType(Keyword, DS.getTypeSpecScope(), + Result); } - if (D->isInvalidDecl()) TheDeclarator.setInvalidType(true); break; @@ -300,28 +302,28 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Result = TheSema.GetTypeFromParser(DS.getTypeRep()); if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - if (const ObjCInterfaceType * - Interface = Result->getAs<ObjCInterfaceType>()) { - // It would be nice if protocol qualifiers were only stored with the - // ObjCObjectPointerType. Unfortunately, this isn't possible due - // to the following typedef idiom (which is uncommon, but allowed): - // - // typedef Foo<P> T; - // static void func() { - // Foo<P> *yy; - // T *zz; - // } - Result = Context.getObjCInterfaceType(Interface->getDecl(), - (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); - } else if (Result->isObjCIdType()) + if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) { + // Silently drop any existing protocol qualifiers. + // TODO: determine whether that's the right thing to do. + if (ObjT->getNumProtocols()) + Result = ObjT->getBaseType(); + + if (DS.getNumProtocolQualifiers()) + Result = Context.getObjCObjectType(Result, + (ObjCProtocolDecl**) PQ, + DS.getNumProtocolQualifiers()); + } else if (Result->isObjCIdType()) { // id<protocol-list> - Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); - else if (Result->isObjCClassType()) { + Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, + (ObjCProtocolDecl**) PQ, + DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectPointerType(Result); + } else if (Result->isObjCClassType()) { // Class<protocol-list> - Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy, - (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, + (ObjCProtocolDecl**) PQ, + DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectPointerType(Result); } else { TheSema.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); @@ -504,7 +506,7 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, Qs.removeRestrict(); } - assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType"); + assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); // Build the pointer type. return Context.getQualifiedType(Context.getPointerType(T), Qs); @@ -659,7 +661,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, // array, accept it as a GNU extension: C99 6.7.2.1p2. if (EltTy->getDecl()->hasFlexibleArrayMember()) Diag(Loc, diag::ext_flexible_array_in_array) << T; - } else if (T->isObjCInterfaceType()) { + } else if (T->isObjCObjectType()) { Diag(Loc, diag::err_objc_array_of_interfaces) << T; return QualType(); } @@ -678,7 +680,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets); else T = Context.getIncompleteArrayType(T, ASM, Quals); - } else if (ArraySize->isValueDependent()) { + } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || (!T->isDependentType() && !T->isIncompleteType() && @@ -707,11 +709,23 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOptions().C99) { - if (ArraySize && !ArraySize->isTypeDependent() && - !ArraySize->isValueDependent() && - !ArraySize->isIntegerConstantExpr(Context)) - Diag(Loc, getLangOptions().CPlusPlus? diag::err_vla_cxx : diag::ext_vla); - else if (ASM != ArrayType::Normal || Quals != 0) + if (T->isVariableArrayType()) { + // Prohibit the use of non-POD types in VLAs. + if (!T->isDependentType() && + !Context.getBaseElementType(T)->isPODType()) { + Diag(Loc, diag::err_vla_non_pod) + << Context.getBaseElementType(T); + return QualType(); + } + // Prohibit the use of VLAs during template argument deduction. + else if (isSFINAEContext()) { + Diag(Loc, diag::err_vla_in_sfinae); + return QualType(); + } + // Just extwarn about VLAs. + else + Diag(Loc, diag::ext_vla); + } else if (ASM != ArrayType::Normal || Quals != 0) Diag(Loc, getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx : diag::ext_c99_array_usage); @@ -995,10 +1009,10 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; case Declarator::MemberContext: switch (cast<TagDecl>(CurContext)->getTagKind()) { - case TagDecl::TK_enum: assert(0 && "unhandled tag kind"); break; - case TagDecl::TK_struct: Error = 1; /* Struct member */ break; - case TagDecl::TK_union: Error = 2; /* Union member */ break; - case TagDecl::TK_class: Error = 3; /* Class member */ break; + case TTK_Enum: assert(0 && "unhandled tag kind"); break; + case TTK_Struct: Error = 1; /* Struct member */ break; + case TTK_Union: Error = 2; /* Union member */ break; + case TTK_Class: Error = 3; /* Class member */ break; } break; case Declarator::CXXCatchContext: @@ -1056,13 +1070,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, D.setInvalidType(true); // Build the type anyway. } - if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) { - const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>(); - T = Context.getObjCObjectPointerType(T, - const_cast<ObjCProtocolDecl **>( - OIT->qual_begin()), - OIT->getNumProtocols(), - DeclType.Ptr.TypeQuals); + if (getLangOptions().ObjC1 && T->getAs<ObjCObjectType>()) { + T = Context.getObjCObjectPointerType(T); + T = Context.getCVRQualifiedType(T, DeclType.Ptr.TypeQuals); break; } T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name); @@ -1301,7 +1311,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case NestedNameSpecifier::TypeSpecWithTemplate: ClsType = QualType(NNS->getAsType(), 0); if (NNSPrefix) - ClsType = Context.getQualifiedNameType(NNSPrefix, ClsType); + ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType); break; } } else { @@ -1401,7 +1411,18 @@ namespace { } void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); + } + void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + // Handle the base type, which might not have been written explicitly. + if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { + TL.setHasBaseTypeAsWritten(false); + TL.getBaseLoc().initialize(SourceLocation()); + } else { + TL.setHasBaseTypeAsWritten(true); + Visit(TL.getBaseLoc()); + } + // Protocol qualifiers. if (DS.getProtocolQualifiers()) { assert(TL.getNumProtocols() > 0); assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); @@ -1416,34 +1437,8 @@ namespace { } } void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); - TL.setStarLoc(SourceLocation()); - - if (DS.getProtocolQualifiers()) { - assert(TL.getNumProtocols() > 0); - assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); - TL.setHasProtocolsAsWritten(true); - TL.setLAngleLoc(DS.getProtocolLAngleLoc()); - TL.setRAngleLoc(DS.getSourceRange().getEnd()); - for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) - TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); - - } else { - assert(TL.getNumProtocols() == 0); - TL.setHasProtocolsAsWritten(false); - TL.setLAngleLoc(SourceLocation()); - TL.setRAngleLoc(SourceLocation()); - } - - // This might not have been written with an inner type. - if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { - TL.setHasBaseTypeAsWritten(false); - TL.getBaseTypeLoc().initialize(SourceLocation()); - } else { - TL.setHasBaseTypeAsWritten(true); - Visit(TL.getBaseTypeLoc()); - } + Visit(TL.getPointeeLoc()); } void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { TypeSourceInfo *TInfo = 0; @@ -1456,9 +1451,15 @@ namespace { return; } - TemplateSpecializationTypeLoc OldTL = - cast<TemplateSpecializationTypeLoc>(TInfo->getTypeLoc()); - TL.copy(OldTL); + TypeLoc OldTL = TInfo->getTypeLoc(); + if (TInfo->getType()->getAs<ElaboratedType>()) { + ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(OldTL); + TemplateSpecializationTypeLoc NamedTL = + cast<TemplateSpecializationTypeLoc>(ElabTL.getNamedTypeLoc()); + TL.copy(NamedTL); + } + else + TL.copy(cast<TemplateSpecializationTypeLoc>(OldTL)); } void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr); @@ -1489,6 +1490,44 @@ namespace { TL.setBuiltinLoc(DS.getTypeSpecWidthLoc()); } } + void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + ElaboratedTypeKeyword Keyword + = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType()); + if (Keyword == ETK_Typename) { + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); + if (TInfo) { + TL.copy(cast<ElaboratedTypeLoc>(TInfo->getTypeLoc())); + return; + } + } + TL.setKeywordLoc(Keyword != ETK_None + ? DS.getTypeSpecTypeLoc() + : SourceLocation()); + const CXXScopeSpec& SS = DS.getTypeSpecScope(); + TL.setQualifierRange(SS.isEmpty() ? SourceRange(): SS.getRange()); + Visit(TL.getNextTypeLoc().getUnqualifiedLoc()); + } + void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + ElaboratedTypeKeyword Keyword + = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType()); + if (Keyword == ETK_Typename) { + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); + if (TInfo) { + TL.copy(cast<DependentNameTypeLoc>(TInfo->getTypeLoc())); + return; + } + } + TL.setKeywordLoc(Keyword != ETK_None + ? DS.getTypeSpecTypeLoc() + : SourceLocation()); + const CXXScopeSpec& SS = DS.getTypeSpecScope(); + TL.setQualifierRange(SS.isEmpty() ? SourceRange() : SS.getRange()); + // FIXME: load appropriate source location. + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + } + void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(DS.getTypeSpecTypeLoc()); @@ -1516,10 +1555,6 @@ namespace { void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Pointer); TL.setStarLoc(Chunk.Loc); - TL.setHasBaseTypeAsWritten(true); - TL.setHasProtocolsAsWritten(false); - TL.setLAngleLoc(SourceLocation()); - TL.setRAngleLoc(SourceLocation()); } void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::MemberPointer); @@ -1642,6 +1677,16 @@ bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) { T2 = T2MPType->getPointeeType(); return true; } + + if (getLangOptions().ObjC1) { + const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(), + *T2OPType = T2->getAs<ObjCObjectPointerType>(); + if (T1OPType && T2OPType) { + T1 = T1OPType->getPointeeType(); + T2 = T2OPType->getPointeeType(); + return true; + } + } return false; } @@ -1704,7 +1749,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, } Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt addrSpace(32); - if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { + if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() || + !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int) << ASArgExpr->getSourceRange(); Attr.setInvalid(); @@ -1810,7 +1856,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { llvm::APSInt NumParams(32); // The warning is emitted elsewhere - if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) + if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() || + !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) return false; Type = S.Context.getRegParmType(Type, NumParams.getZExtValue()); @@ -1838,6 +1885,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { case AttributeList::AT_cdecl: CC = CC_C; break; case AttributeList::AT_fastcall: CC = CC_X86FastCall; break; case AttributeList::AT_stdcall: CC = CC_X86StdCall; break; + case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break; default: llvm_unreachable("unexpected attribute kind"); return false; } @@ -1895,7 +1943,8 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S } Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt vecSize(32); - if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { + if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() || + !sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "vector_size" << sizeExpr->getSourceRange(); Attr.setInvalid(); @@ -1962,6 +2011,7 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result, case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: case AttributeList::AT_stdcall: + case AttributeList::AT_thiscall: case AttributeList::AT_regparm: // Don't process these on the DeclSpec. if (IsDeclSpec || @@ -2082,15 +2132,21 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, std::make_pair(SourceLocation(), PDiag(0))); } -/// \brief Retrieve a version of the type 'T' that is qualified by the -/// nested-name-specifier contained in SS. -QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) { - if (!SS.isSet() || SS.isInvalid() || T.isNull()) +/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword +/// and qualified by the nested-name-specifier contained in SS. +QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, + const CXXScopeSpec &SS, QualType T) { + if (T.isNull()) return T; - - NestedNameSpecifier *NNS - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - return Context.getQualifiedNameType(NNS, T); + NestedNameSpecifier *NNS; + if (SS.isValid()) + NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + else { + if (Keyword == ETK_None) + return T; + NNS = 0; + } + return Context.getElaboratedType(Keyword, NNS, T); } QualType Sema::BuildTypeofExprType(Expr *E) { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 5ce268bd9eb4..a18701e61d94 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -344,8 +344,8 @@ public: OwningStmtResult Transform##Node(Node *S); #define EXPR(Node, Parent) \ OwningExprResult Transform##Node(Node *E); -#define ABSTRACT_EXPR(Node, Parent) -#include "clang/AST/StmtNodes.def" +#define ABSTRACT_STMT(Stmt) +#include "clang/AST/StmtNodes.inc" /// \brief Build a new pointer type given its pointee type. /// @@ -492,11 +492,6 @@ public: return SemaRef.Context.getTypeDeclType(Enum); } - /// \brief Build a new elaborated type. - QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag) { - return SemaRef.Context.getElaboratedType(T, Tag); - } - /// \brief Build a new typeof(expr) type. /// /// By default, performs semantic analysis when building the typeof type. @@ -525,19 +520,19 @@ public: /// \brief Build a new qualified name type. /// - /// By default, builds a new QualifiedNameType type from the - /// nested-name-specifier and the named type. Subclasses may override - /// this routine to provide different behavior. - QualType RebuildQualifiedNameType(NestedNameSpecifier *NNS, QualType Named) { - return SemaRef.Context.getQualifiedNameType(NNS, Named); + /// By default, builds a new ElaboratedType type from the keyword, + /// the nested-name-specifier and the named type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, QualType Named) { + return SemaRef.Context.getElaboratedType(Keyword, NNS, Named); } /// \brief Build a new typename type that refers to a template-id. /// - /// By default, builds a new DependentNameType type from the - /// nested-name-specifier - /// and the given type. Subclasses may override this routine to provide - /// different behavior. + /// By default, builds a new DependentNameType type from the + /// nested-name-specifier and the given type. Subclasses may override + /// this routine to provide different behavior. QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType T) { if (NNS->isDependent()) { @@ -548,50 +543,48 @@ public: return SemaRef.Context.getDependentNameType(Keyword, NNS, cast<TemplateSpecializationType>(T)); } - - // FIXME: Handle elaborated-type-specifiers separately. - return SemaRef.Context.getQualifiedNameType(NNS, T); + + return SemaRef.Context.getElaboratedType(Keyword, NNS, T); } /// \brief Build a new typename type that refers to an identifier. /// /// By default, performs semantic analysis when building the typename type - /// (or qualified name type). Subclasses may override this routine to provide + /// (or elaborated type). Subclasses may override this routine to provide /// different behavior. - QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, + QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Id, - SourceRange SR) { + SourceLocation KeywordLoc, + SourceRange NNSRange, + SourceLocation IdLoc) { CXXScopeSpec SS; SS.setScopeRep(NNS); - + SS.setRange(NNSRange); + if (NNS->isDependent()) { // If the name is still dependent, just build a new dependent name type. if (!SemaRef.computeDeclContext(SS)) return SemaRef.Context.getDependentNameType(Keyword, NNS, Id); } - TagDecl::TagKind Kind = TagDecl::TK_enum; - switch (Keyword) { - case ETK_None: - // Fall through. - case ETK_Typename: - return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR); - - case ETK_Class: Kind = TagDecl::TK_class; break; - case ETK_Struct: Kind = TagDecl::TK_struct; break; - case ETK_Union: Kind = TagDecl::TK_union; break; - case ETK_Enum: Kind = TagDecl::TK_enum; break; - } - - // We had a dependent elaborated-type-specifier that as been transformed + if (Keyword == ETK_None || Keyword == ETK_Typename) + return SemaRef.CheckTypenameType(Keyword, NNS, *Id, + KeywordLoc, NNSRange, IdLoc); + + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); + + // We had a dependent elaborated-type-specifier that has been transformed // into a non-dependent elaborated-type-specifier. Find the tag we're // referring to. - LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName); + LookupResult Result(SemaRef, Id, IdLoc, Sema::LookupTagName); DeclContext *DC = SemaRef.computeDeclContext(SS, false); if (!DC) return QualType(); + if (SemaRef.RequireCompleteDeclContext(SS, DC)) + return QualType(); + TagDecl *Tag = 0; SemaRef.LookupQualifiedName(Result, DC); switch (Result.getResultKind()) { @@ -615,22 +608,20 @@ public: if (!Tag) { // FIXME: Would be nice to highlight just the source range. - SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope) + SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) << Kind << Id << DC; return QualType(); } - - // FIXME: Terrible location information - if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) { - SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id; + + if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, IdLoc, *Id)) { + SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id; SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); return QualType(); } // Build the elaborated-type-specifier type. QualType T = SemaRef.Context.getTypeDeclType(Tag); - T = SemaRef.Context.getQualifiedNameType(NNS, T); - return SemaRef.Context.getElaboratedType(T, Kind); + return SemaRef.Context.getElaboratedType(Keyword, NNS, T); } /// \brief Build a new nested-name-specifier given the prefix and an @@ -769,9 +760,11 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - OwningStmtResult RebuildSwitchStmtStart(Sema::FullExprArg Cond, + OwningStmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, + Sema::ExprArg Cond, VarDecl *CondVar) { - return getSema().ActOnStartOfSwitchStmt(Cond, DeclPtrTy::make(CondVar)); + return getSema().ActOnStartOfSwitchStmt(SwitchLoc, move(Cond), + DeclPtrTy::make(CondVar)); } /// \brief Attach the body to the switch statement. @@ -792,8 +785,8 @@ public: Sema::FullExprArg Cond, VarDecl *CondVar, StmtArg Body) { - return getSema().ActOnWhileStmt(WhileLoc, Cond, DeclPtrTy::make(CondVar), - move(Body)); + return getSema().ActOnWhileStmt(WhileLoc, Cond, + DeclPtrTy::make(CondVar), move(Body)); } /// \brief Build a new do-while statement. @@ -1966,13 +1959,13 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) { #define STMT(Node, Parent) \ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S)); #define EXPR(Node, Parent) -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" // Transform expressions by calling TransformExpr. #define STMT(Node, Parent) -#define ABSTRACT_EXPR(Node, Parent) +#define ABSTRACT_STMT(Stmt) #define EXPR(Node, Parent) case Stmt::Node##Class: -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" { Sema::OwningExprResult E = getDerived().TransformExpr(cast<Expr>(S)); if (E.isInvalid()) @@ -1994,10 +1987,10 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E) { switch (E->getStmtClass()) { case Stmt::NoStmtClass: break; #define STMT(Node, Parent) case Stmt::Node##Class: break; -#define ABSTRACT_EXPR(Node, Parent) +#define ABSTRACT_STMT(Stmt) #define EXPR(Node, Parent) \ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E)); -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" } return SemaRef.Owned(E->Retain()); @@ -2457,23 +2450,15 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, return QualType(); QualType Result = TL.getType(); - if (PointeeType->isObjCInterfaceType()) { + if (PointeeType->getAs<ObjCObjectType>()) { // A dependent pointer type 'T *' has is being transformed such // that an Objective-C class type is being replaced for 'T'. The // resulting pointer type is an ObjCObjectPointerType, not a // PointerType. - const ObjCInterfaceType *IFace = PointeeType->getAs<ObjCInterfaceType>(); - Result = SemaRef.Context.getObjCObjectPointerType(PointeeType, - const_cast<ObjCProtocolDecl **>( - IFace->qual_begin()), - IFace->getNumProtocols()); + Result = SemaRef.Context.getObjCObjectPointerType(PointeeType); - ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result); - NewT.setStarLoc(TL.getSigilLoc()); - NewT.setHasProtocolsAsWritten(false); - NewT.setLAngleLoc(SourceLocation()); - NewT.setRAngleLoc(SourceLocation()); - NewT.setHasBaseTypeAsWritten(true); + ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result); + NewT.setStarLoc(TL.getStarLoc()); return Result; } @@ -3144,31 +3129,6 @@ QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB, return Result; } -template <typename Derived> -QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, - ElaboratedTypeLoc TL, - QualType ObjectType) { - ElaboratedType *T = TL.getTypePtr(); - - // FIXME: this should be a nested type. - QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); - if (Underlying.isNull()) - return QualType(); - - QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - Underlying != T->getUnderlyingType()) { - Result = getDerived().RebuildElaboratedType(Underlying, T->getTagKind()); - if (Result.isNull()) - return QualType(); - } - - ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - - return Result; -} - template<typename Derived> QualType TreeTransform<Derived>::TransformInjectedClassNameType( TypeLocBuilder &TLB, @@ -3273,32 +3233,54 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( template<typename Derived> QualType -TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB, - QualifiedNameTypeLoc TL, - QualType ObjectType) { - QualifiedNameType *T = TL.getTypePtr(); - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - SourceRange(), - ObjectType); - if (!NNS) - return QualType(); +TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, + ElaboratedTypeLoc TL, + QualType ObjectType) { + ElaboratedType *T = TL.getTypePtr(); - QualType Named = getDerived().TransformType(T->getNamedType()); - if (Named.isNull()) - return QualType(); + NestedNameSpecifier *NNS = 0; + // NOTE: the qualifier in an ElaboratedType is optional. + if (T->getQualifier() != 0) { + NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), + TL.getQualifierRange(), + ObjectType); + if (!NNS) + return QualType(); + } + + QualType NamedT; + // FIXME: this test is meant to workaround a problem (failing assertion) + // occurring if directly executing the code in the else branch. + if (isa<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc())) { + TemplateSpecializationTypeLoc OldNamedTL + = cast<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc()); + const TemplateSpecializationType* OldTST + = OldNamedTL.getType()->template getAs<TemplateSpecializationType>(); + NamedT = TransformTemplateSpecializationType(OldTST, ObjectType); + if (NamedT.isNull()) + return QualType(); + TemplateSpecializationTypeLoc NewNamedTL + = TLB.push<TemplateSpecializationTypeLoc>(NamedT); + NewNamedTL.copy(OldNamedTL); + } + else { + NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc()); + if (NamedT.isNull()) + return QualType(); + } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || NNS != T->getQualifier() || - Named != T->getNamedType()) { - Result = getDerived().RebuildQualifiedNameType(NNS, Named); + NamedT != T->getNamedType()) { + Result = getDerived().RebuildElaboratedType(T->getKeyword(), NNS, NamedT); if (Result.isNull()) return QualType(); } - QualifiedNameTypeLoc NewTL = TLB.push<QualifiedNameTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); + ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); return Result; } @@ -3309,11 +3291,9 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB, QualType ObjectType) { DependentNameType *T = TL.getTypePtr(); - /* FIXME: preserve source information better than this */ - SourceRange SR(TL.getNameLoc()); - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR, + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), + TL.getQualifierRange(), ObjectType); if (!NNS) return QualType(); @@ -3331,18 +3311,38 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB, NewTemplateId == QualType(TemplateId, 0)) return QualType(T, 0); - Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, NewTemplateId); } else { - Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, - T->getIdentifier(), SR); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + T->getIdentifier(), + TL.getKeywordLoc(), + TL.getQualifierRange(), + TL.getNameLoc()); } if (Result.isNull()) return QualType(); - DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - + if (const ElaboratedType* ElabT = Result->getAs<ElaboratedType>()) { + QualType NamedT = ElabT->getNamedType(); + if (isa<TemplateSpecializationType>(NamedT)) { + TemplateSpecializationTypeLoc NamedTLoc + = TLB.push<TemplateSpecializationTypeLoc>(NamedT); + // FIXME: fill locations + NamedTLoc.initializeLocal(TL.getNameLoc()); + } else { + TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc()); + } + ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); + } + else { + DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); + NewTL.setNameLoc(TL.getNameLoc()); + } return Result; } @@ -3352,6 +3352,17 @@ TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, ObjCInterfaceTypeLoc TL, QualType ObjectType) { // ObjCInterfaceType is never dependent. + TLB.pushFullCopy(TL); + return TL.getType(); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, + ObjCObjectTypeLoc TL, + QualType ObjectType) { + // ObjCObjectType is never dependent. + TLB.pushFullCopy(TL); return TL.getType(); } @@ -3361,6 +3372,7 @@ TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, ObjCObjectPointerTypeLoc TL, QualType ObjectType) { // ObjCObjectPointerType is never dependent. + TLB.pushFullCopy(TL); return TL.getType(); } @@ -3489,10 +3501,23 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { if (Cond.isInvalid()) return SemaRef.StmtError(); + + // Convert the condition to a boolean value. + if (S->getCond()) { + OwningExprResult CondE = getSema().ActOnBooleanCondition(0, + S->getIfLoc(), + move(Cond)); + if (CondE.isInvalid()) + return getSema().StmtError(); + + Cond = move(CondE); + } } Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); - + if (!S->getConditionVariable() && S->getCond() && !FullCond->get()) + return SemaRef.StmtError(); + // Transform the "then" branch. OwningStmtResult Then = getDerived().TransformStmt(S->getThen()); if (Then.isInvalid()) @@ -3536,11 +3561,10 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) { return SemaRef.StmtError(); } - Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); - // Rebuild the switch statement. - OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(FullCond, - ConditionVar); + OwningStmtResult Switch + = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), move(Cond), + ConditionVar); if (Switch.isInvalid()) return SemaRef.StmtError(); @@ -3573,9 +3597,21 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { if (Cond.isInvalid()) return SemaRef.StmtError(); + + if (S->getCond()) { + // Convert the condition to a boolean value. + OwningExprResult CondE = getSema().ActOnBooleanCondition(0, + S->getWhileLoc(), + move(Cond)); + if (CondE.isInvalid()) + return getSema().StmtError(); + Cond = move(CondE); + } } Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); + if (!S->getConditionVariable() && S->getCond() && !FullCond->get()) + return SemaRef.StmtError(); // Transform the body OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); @@ -3588,23 +3624,23 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { Body.get() == S->getBody()) return SemaRef.Owned(S->Retain()); - return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, ConditionVar, - move(Body)); + return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, + ConditionVar, move(Body)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformDoStmt(DoStmt *S) { - // Transform the condition - OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); - if (Cond.isInvalid()) - return SemaRef.StmtError(); - // Transform the body OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) return SemaRef.StmtError(); + // Transform the condition + OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + if (!getDerived().AlwaysRebuild() && Cond.get() == S->getCond() && Body.get() == S->getBody()) @@ -3639,13 +3675,32 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { if (Cond.isInvalid()) return SemaRef.StmtError(); + + if (S->getCond()) { + // Convert the condition to a boolean value. + OwningExprResult CondE = getSema().ActOnBooleanCondition(0, + S->getForLoc(), + move(Cond)); + if (CondE.isInvalid()) + return getSema().StmtError(); + + Cond = move(CondE); + } } + Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); + if (!S->getConditionVariable() && S->getCond() && !FullCond->get()) + return SemaRef.StmtError(); + // Transform the increment OwningExprResult Inc = getDerived().TransformExpr(S->getInc()); if (Inc.isInvalid()) return SemaRef.StmtError(); + Sema::FullExprArg FullInc(getSema().MakeFullExpr(Inc)); + if (S->getInc() && !FullInc->get()) + return SemaRef.StmtError(); + // Transform the body OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) @@ -3653,16 +3708,14 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { if (!getDerived().AlwaysRebuild() && Init.get() == S->getInit() && - Cond.get() == S->getCond() && + FullCond->get() == S->getCond() && Inc.get() == S->getInc() && Body.get() == S->getBody()) return SemaRef.Owned(S->Retain()); return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(), - move(Init), getSema().MakeFullExpr(Cond), - ConditionVar, - getSema().MakeFullExpr(Inc), - S->getRParenLoc(), move(Body)); + move(Init), FullCond, ConditionVar, + FullInc, S->getRParenLoc(), move(Body)); } template<typename Derived> @@ -5160,6 +5213,9 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { // transform the constructor arguments (if any). ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef); for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) { + if (getDerived().DropCallArgument(E->getConstructorArg(I))) + break; + OwningExprResult Arg = getDerived().TransformExpr(E->getConstructorArg(I)); if (Arg.isInvalid()) return SemaRef.ExprError(); @@ -5855,7 +5911,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) R.resolveKind(); // Determine the naming class. - if (!Old->getNamingClass()) { + if (Old->getNamingClass()) { CXXRecordDecl *NamingClass = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl( Old->getMemberLoc(), diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c index 209ca6531cc2..1c600276ba43 100644 --- a/test/Analysis/dead-stores.c +++ b/test/Analysis/dead-stores.c @@ -450,3 +450,15 @@ int f26_nestedblocks() { return y; } +// The FOREACH macro in QT uses 'break' statements within statement expressions +// placed within the increment code of for loops. +void rdar8014335() { + for (int i = 0 ; i != 10 ; ({ break; })) { + for ( ; ; ({ ++i; break; })) ; + // Note that the next value stored to 'i' is never executed + // because the next statement to be executed is the 'break' + // in the increment code of the first loop. + i = i * 3; // expected-warning{{Value stored to 'i' is never read}} + } +} + diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c index acaf74ded996..50c1a54d1016 100644 --- a/test/Analysis/inline.c +++ b/test/Analysis/inline.c @@ -1,5 +1,5 @@ -// RUN: false -// XFAIL: * +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s + int f1() { int y = 1; y++; diff --git a/test/Analysis/inline2.c b/test/Analysis/inline2.c index ec965a69c644..efdb75cc6535 100644 --- a/test/Analysis/inline2.c +++ b/test/Analysis/inline2.c @@ -1,5 +1,4 @@ -// RUN: false -// XFAIL: * +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s // Test parameter 'a' is registered to LiveVariables analysis data although it // is not referenced in the function body. diff --git a/test/Analysis/inline3.c b/test/Analysis/inline3.c index 8f45858bb949..884b3ed9dc25 100644 --- a/test/Analysis/inline3.c +++ b/test/Analysis/inline3.c @@ -1,5 +1,4 @@ -// RUN: false -// XFAIL: * +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s // Test when entering f1(), we set the right AnalysisContext to Environment. // Otherwise, block-level expr '1 && a' would not be block-level. diff --git a/test/Analysis/inline4.c b/test/Analysis/inline4.c index b2b3c346e374..5a1d193beb29 100644 --- a/test/Analysis/inline4.c +++ b/test/Analysis/inline4.c @@ -1,5 +1,5 @@ -// RUN: false -// XFAIL: * +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s + int g(int a) { return a; } diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index 21b6d46a245e..fe24bc19e61c 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -6,16 +6,16 @@ void *realloc(void *ptr, size_t size); void *calloc(size_t nmemb, size_t size); void f1() { - int *p = malloc(10); + int *p = malloc(12); return; // expected-warning{{Allocated memory never released. Potential memory leak.}} } void f1_b() { - int *p = malloc(10); // expected-warning{{Allocated memory never released. Potential memory leak.}} + int *p = malloc(12); // expected-warning{{Allocated memory never released. Potential memory leak.}} } void f2() { - int *p = malloc(10); + int *p = malloc(12); free(p); free(p); // expected-warning{{Try to free a memory block that has been released}} } @@ -25,7 +25,7 @@ void f2() { // or inter-procedural analysis, this is a conservative answer. int *f3() { static int *p = 0; - p = malloc(10); + p = malloc(12); return p; // no-warning } @@ -34,18 +34,18 @@ int *f3() { // functions or inter-procedural analysis, this is a conservative answer. static int *p_f4 = 0; int *f4() { - p_f4 = malloc(10); + p_f4 = malloc(12); return p_f4; // no-warning } int *f5() { - int *q = malloc(10); + int *q = malloc(12); q = realloc(q, 20); return q; // no-warning } void f6() { - int *p = malloc(10); + int *p = malloc(12); if (!p) return; // no-warning else @@ -67,3 +67,13 @@ void f7() { free(x); x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}} } + +void PR6123() { + int *x = malloc(11); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} +} + +void PR7217() { + int *buf = malloc(2); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} + buf[1] = 'c'; // not crash + +} diff --git a/test/Analysis/method-call.cpp b/test/Analysis/method-call.cpp index dd891596c5dc..47f14447d6bd 100644 --- a/test/Analysis/method-call.cpp +++ b/test/Analysis/method-call.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -verify %s +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s struct A { int x; A(int a) { x = a; } diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m index 42551417a2a5..52516abc397b 100644 --- a/test/Analysis/misc-ps-region-store.m +++ b/test/Analysis/misc-ps-region-store.m @@ -1014,3 +1014,22 @@ void pr6854(void * arg) { float f = *(float*) a; } +// <rdar://problem/8032791> False positive due to symbolic store not find +// value because of 'const' qualifier +double rdar_8032791_2(); +double rdar_8032791_1() { + struct R8032791 { double x[2]; double y; } + data[3] = { + {{1.0, 3.0}, 3.0}, // 1 2 3 + {{1.0, 1.0}, 0.0}, // 1 1 2 2 3 3 + {{1.0, 3.0}, 1.0} // 1 2 3 + }; + + double x = 0.0; + for (unsigned i = 0 ; i < 3; i++) { + const struct R8032791 *p = &data[i]; + x += p->y + rdar_8032791_2(); // no-warning + } + return x; +} + diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index 2b21eec18cd7..8323c62390e8 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -8,6 +8,10 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s +#ifndef __clang_analyzer__ +#error __clang__analyzer__ not defined +#endif + typedef struct objc_ivar *Ivar; typedef struct objc_selector *SEL; typedef signed char BOOL; @@ -957,3 +961,13 @@ void pr6938_b() { }) == 0) { } } + +//===----------------------------------------------------------------------===// +// <rdar://problem/7979430> - The CFG for code containing an empty +// @synchronized block was previously broken (and would crash the analyzer). +//===----------------------------------------------------------------------===// + +void r7979430(id x) { + @synchronized(x) {} +} + diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index 3f79c0c7f46d..9e5151d16704 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -1332,3 +1332,15 @@ void test_blocks_1_indirect_retain_via_call(void) { ^(NSObject *o){ [o retain]; }(number); } +//===--------------------------------------------------------------------===// +// Test sending message to super that returns an object alias. Previously +// this caused a crash in the analyzer. +//===--------------------------------------------------------------------===// + +@interface Rdar8015556 : NSObject {} @end +@implementation Rdar8015556 +- (id)retain { + return [super retain]; +} +@end + diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp index 991698d5dcca..563ae4f63c4d 100644 --- a/test/CXX/class.access/class.friend/p1.cpp +++ b/test/CXX/class.access/class.friend/p1.cpp @@ -189,7 +189,7 @@ namespace test4 { struct Inequal {}; bool test() { Holder<Inequal> a, b; - return a == b; // expected-note {{requested here}} + return a == b; // expected-note {{requested here}} } } diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp index 1cd896613679..e8afbe7a3924 100644 --- a/test/CXX/class.access/p4.cpp +++ b/test/CXX/class.access/p4.cpp @@ -97,7 +97,7 @@ namespace test2 { A A::foo; // okay class B : A { }; // expected-error {{base class 'test2::A' has private constructor}} - B b; + B b; // expected-note{{implicit default constructor}} class C : virtual A { public: @@ -105,7 +105,7 @@ namespace test2 { }; class D : C { }; // expected-error {{inherited virtual base class 'test2::A' has private constructor}} - D d; + D d; // expected-note{{implicit default constructor}} } // Implicit destructor calls. @@ -143,13 +143,15 @@ namespace test3 { }; class Derived3 : // expected-error 2 {{inherited virtual base class 'Base<2>' has private destructor}} \ - // expected-error 2 {{inherited virtual base class 'Base<3>' has private destructor}} + // expected-error 2 {{inherited virtual base class 'Base<3>' has private destructor}} \ + // expected-note 2{{implicit default constructor}} Base<0>, // expected-error 2 {{base class 'Base<0>' has private destructor}} virtual Base<1>, // expected-error 2 {{base class 'Base<1>' has private destructor}} Base2, // expected-error 2 {{base class 'test3::Base2' has private destructor}} virtual Base3 - {}; - Derived3 d3; + {}; + Derived3 d3; // expected-note {{implicit default constructor}}\ + // expected-note{{implicit default destructor}}} } // Conversion functions. @@ -205,13 +207,13 @@ namespace test5 { class Test1 { A a; }; // expected-error {{private member}} void test1() { Test1 a; - a = Test1(); + a = Test1(); // expected-note{{implicit default copy}} } class Test2 : A {}; // expected-error {{private member}} void test2() { Test2 a; - a = Test2(); + a = Test2(); // expected-note{{implicit default copy}} } } @@ -224,12 +226,12 @@ namespace test6 { class Test1 { A a; }; // expected-error {{field of type 'test6::A' has private copy constructor}} void test1(const Test1 &t) { - Test1 a = t; + Test1 a = t; // expected-note{{implicit default copy}} } class Test2 : A {}; // expected-error {{base class 'test6::A' has private copy constructor}} void test2(const Test2 &t) { - Test2 a = t; + Test2 a = t; // expected-note{{implicit default copy}} } } diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp index fd2df010fc9b..466097171c8d 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp @@ -81,3 +81,18 @@ namespace test2 { template struct Derived<int>; // expected-note {{in instantiation of template class}} } + +// Redeclarations are okay in a function. +namespace test3 { + namespace N { + int f(int); + typedef int type; + } + + void g() { + using N::f; + using N::f; + using N::type; + using N::type; + } +} diff --git a/test/CXX/expr/expr.post/expr.ref/p3.cpp b/test/CXX/expr/expr.post/expr.ref/p3.cpp new file mode 100644 index 000000000000..98771d34b63d --- /dev/null +++ b/test/CXX/expr/expr.post/expr.ref/p3.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +template<typename T> struct Node { + int lhs; + void splay( ) + { + Node<T> n[1]; + (void)n->lhs; + } +}; + +void f() { + Node<int> n; + return n.splay(); +} diff --git a/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/test/CXX/temp/temp.decls/temp.friend/p4.cpp new file mode 100644 index 000000000000..226ac0fc622f --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.friend/p4.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template<typename T> +struct X1 { + friend void f6(int) { } // expected-error{{redefinition of}} \ + // expected-note{{previous definition}} +}; + +X1<int> x1a; +X1<float> x1b; // expected-note {{in instantiation of}} diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp index 1b7310f00055..90d29497f4b2 100644 --- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp @@ -16,7 +16,8 @@ void test_f1(int *ip, float fv) { } // TODO: this diagnostic can and should improve -template<typename T> void f2(T*, T*); // expected-note 2 {{candidate template ignored: failed template argument deduction}} +template<typename T> void f2(T*, T*); // expected-note {{candidate template ignored: failed template argument deduction}} \ +// expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'float')}} struct ConvToIntPtr { operator int*() const; diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp index 6edf079b3524..1b240cc98fc7 100644 --- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s namespace test0 { - template<class T> void apply(T x, void (*f)(T)) { f(x); } // expected-note 2 {{failed template argument deduction}}\ + template<class T> void apply(T x, void (*f)(T)) { f(x); } // expected-note 2 {{candidate template ignored: deduced conflicting types for parameter 'T'}}\ // expected-note {{no overload of 'temp2' matching 'void (*)(int)'}} template<class A> void temp(A); diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp index 2a7f16dc6b69..bf5f96225dad 100644 --- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s template<int i> class A { }; -template<short s> void f(A<s>); // expected-note{{failed template argument deduction}} +template<short s> void f(A<s>); // expected-note{{candidate template ignored: substitution failure}} void k1() { A<1> a; @@ -15,14 +15,14 @@ void k2() { g(b); // OK: cv-qualifiers are ignored on template parameter types } -template<short s> void h(int (&)[s]); // expected-note{{failed template argument deduction}} +template<short s> void h(int (&)[s]); // expected-note{{candidate function template not viable: requires 1 argument, but 2 were provided}} void k3() { int array[5]; h(array); h<5>(array); } -template<short s> void h(int (&)[s], A<s>); // expected-note{{failed template argument deduction}} +template<short s> void h(int (&)[s], A<s>); // expected-note{{candidate template ignored: substitution failure}} void k4() { A<5> a; int array[5]; diff --git a/test/CXX/temp/temp.names/p2.cpp b/test/CXX/temp/temp.names/p2.cpp new file mode 100644 index 000000000000..93e45dd7e3b0 --- /dev/null +++ b/test/CXX/temp/temp.names/p2.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// Ensure that when enforcing access control an unqualified template name with +// explicit template arguments, we don't lose the context of the name lookup +// because of the required early lookup to determine if it names a template. +namespace PR7163 { + template <typename R, typename P> void h(R (*func)(P)) {} + class C { + template <typename T> static void g(T*) {}; + public: + void f() { h(g<int>); } + }; +} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp index 8538d27f09bc..0da316cc9cef 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp @@ -39,5 +39,5 @@ namespace N { } using namespace N; -template struct X1<int>; // expected-error{{must occur in}} -template void f1(int); // expected-error{{must occur in}} +template struct X1<int>; // expected-warning{{must occur in}} +template void f1(int); // expected-warning{{must occur in}} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p5.cpp b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp index 13fb0492f1a4..7522d02ffa19 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p5.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp @@ -11,7 +11,7 @@ template class Z<int>; // expected-error{{explicit instantiation of non-template // FIXME: This example from the standard is wrong; note posted to CWG reflector // on 10/27/2009 using N::Y; -template class Y<int>; // expected-error{{must occur in}} +template class Y<int>; // expected-warning{{must occur in}} template class N::Y<char*>; template void N::Y<double>::mf(); diff --git a/test/CodeCompletion/call.c b/test/CodeCompletion/call.c index 8210389ffa56..8581414bf8c3 100644 --- a/test/CodeCompletion/call.c +++ b/test/CodeCompletion/call.c @@ -6,7 +6,7 @@ void test() { f0(0, 0); g0(0, 0); f1(0, 0); - // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:6 %s -o - | FileCheck -check-prefix=CC1 %s + // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:6 %s -o - | FileCheck -check-prefix=CC1 %s // CHECK-CC1: f0(<#float x#>, float y) // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CC2 %s // CHECK-CC2: f0(float x, <#float y#>) diff --git a/test/CodeCompletion/call.cpp b/test/CodeCompletion/call.cpp index 1df958ed2cc0..46494e7619f5 100644 --- a/test/CodeCompletion/call.cpp +++ b/test/CodeCompletion/call.cpp @@ -17,7 +17,7 @@ void f(); void test() { f(Y(), 0, 0); - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC1 %s + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC1 %s // CHECK-CC1: COMPLETION: Pattern : dynamic_cast<<#type-id#>>(<#expression#>) // CHECK-CC1: f(N::Y y, <#int ZZ#>) // CHECK-CC1-NEXT: f(int i, <#int j#>, int k) diff --git a/test/CodeCompletion/ordinary-name.cpp b/test/CodeCompletion/ordinary-name.cpp index 699b01de74ff..20f661a28035 100644 --- a/test/CodeCompletion/ordinary-name.cpp +++ b/test/CodeCompletion/ordinary-name.cpp @@ -4,7 +4,7 @@ typedef struct t TYPEDEF; void foo() { int y = 17; - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:14 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:6:14 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: COMPLETION: bool // CHECK-CC1-NEXT: COMPLETION: char // CHECK-CC1-NEXT: COMPLETION: class @@ -57,7 +57,7 @@ void foo() { // CHECK-CC1-NEXT: COMPLETION: y : [#int#]y // CHECK-CC1-NEXT: COMPLETION: z : [#void#]z(<#int#>) - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:4:1 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:4:1 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2: COMPLETION: Pattern : asm(<#string-literal#>) // CHECK-CC2-NEXT: COMPLETION: bool // CHECK-CC2-NEXT: COMPLETION: char @@ -93,7 +93,7 @@ void foo() { // CHECK-CC2-NEXT: COMPLETION: wchar_t // CHECK-CC2-NEXT: COMPLETION: X : X - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:1:19 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:1:19 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: COMPLETION: bool // CHECK-CC3-NEXT: COMPLETION: char // CHECK-CC3-NEXT: COMPLETION: class @@ -129,7 +129,7 @@ void foo() { // CHECK-CC3-NEXT: COMPLETION: wchar_t // CHECK-CC3-NEXT: COMPLETION: X : X - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:11 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:6:11 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s // CHECK-CC4: COMPLETION: bool // CHECK-CC4-NEXT: COMPLETION: char // CHECK-CC4-NEXT: COMPLETION: class diff --git a/test/CodeCompletion/truncation.c b/test/CodeCompletion/truncation.c index 134139d78bdf..1b446b7d92ca 100644 --- a/test/CodeCompletion/truncation.c +++ b/test/CodeCompletion/truncation.c @@ -2,6 +2,8 @@ struct +/* foo */ + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s.h:4:8 -o - %s | FileCheck -check-prefix=CC1 %s // CHECK-CC1: X // CHECK-CC1-NEXT: Y @@ -9,3 +11,8 @@ struct // CHECK-CC2: X // CHECK-CC2: Xa // CHECK-CC2: Y + +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:3 -o - %s | FileCheck -check-prefix=CC3 %s +// CHECK-CC3: X +// CHECK-CC3: Xa +// CHECK-CC3: Y diff --git a/test/CodeGen/blocks.c b/test/CodeGen/blocks.c index e7625b19542c..a0f5dae6f44d 100644 --- a/test/CodeGen/blocks.c +++ b/test/CodeGen/blocks.c @@ -12,7 +12,7 @@ struct s0 { int a[64]; }; -// RUN: grep 'internal void @__f2_block_invoke_(.struct.s0\* sret .*, .*, .* byval .*)' %t +// RUN: grep 'internal void @__f2_block_invoke_0(.struct.s0\* sret .*, .*, .* byval .*)' %t struct s0 f2(struct s0 a0) { return ^(struct s0 a1){ return a1; }(a0); } diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c index a4424d77428f..8b6125806eff 100644 --- a/test/CodeGen/builtins.c +++ b/test/CodeGen/builtins.c @@ -163,3 +163,35 @@ void bar() { } // CHECK: } + + +// CHECK: define void @test_float_builtins +void test_float_builtins(float F, double D, long double LD) { + volatile int res; + res = __builtin_isinf(F); + // CHECK: call float @fabsf(float + // CHECK: fcmp oeq float {{.*}}, 0x7FF0000000000000 + + res = __builtin_isinf(D); + // CHECK: call double @fabs(double + // CHECK: fcmp oeq double {{.*}}, 0x7FF0000000000000 + + res = __builtin_isinf(LD); + // CHECK: call x86_fp80 @fabsl(x86_fp80 + // CHECK: fcmp oeq x86_fp80 {{.*}}, 0xK7FFF8000000000000000 + + res = __builtin_isfinite(F); + // CHECK: fcmp oeq float + // CHECK: call float @fabsf + // CHECK: fcmp une float {{.*}}, 0x7FF0000000000000 + // CHECK: and i1 + + res = __builtin_isnormal(F); + // CHECK: fcmp oeq float + // CHECK: call float @fabsf + // CHECK: fcmp ult float {{.*}}, 0x7FF0000000000000 + // CHECK: fcmp uge float {{.*}}, 0x3810000000000000 + // CHECK: and i1 + // CHECK: and i1 +} + diff --git a/test/CodeGen/complex.c b/test/CodeGen/complex.c index ca606109f8b2..055383ebbbe2 100644 --- a/test/CodeGen/complex.c +++ b/test/CodeGen/complex.c @@ -89,3 +89,7 @@ void t6() { --ci1; } +// <rdar://problem/7958272> +double t7(double _Complex c) { + return __builtin_fabs(__real__(c)); +} diff --git a/test/CodeGen/microsoft-call-conv.c b/test/CodeGen/microsoft-call-conv.c new file mode 100644 index 000000000000..95f5fa3f83b5 --- /dev/null +++ b/test/CodeGen/microsoft-call-conv.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -emit-llvm < %s | FileCheck %s + +void __fastcall f1(void); +void __stdcall f2(void); +void __thiscall f3(void); +void __fastcall f4(void) { +// CHECK: define x86_fastcallcc void @f4() + f1(); +// CHECK: call x86_fastcallcc void @f1() +} +void __stdcall f5(void) { +// CHECK: define x86_stdcallcc void @f5() + f2(); +// CHECK: call x86_stdcallcc void @f2() +} +void __thiscall f6(void) { +// CHECK: define x86_thiscallcc void @f6() + f3(); +// CHECK: call x86_thiscallcc void @f3() +} + +// PR5280 +void (__fastcall *pf1)(void) = f1; +void (__stdcall *pf2)(void) = f2; +void (__thiscall *pf3)(void) = f3; +void (__fastcall *pf4)(void) = f4; +void (__stdcall *pf5)(void) = f5; +void (__thiscall *pf6)(void) = f6; + +int main(void) { + f4(); f5(); f6(); + // CHECK: call x86_fastcallcc void @f4() + // CHECK: call x86_stdcallcc void @f5() + // CHECK: call x86_thiscallcc void @f6() + pf1(); pf2(); pf3(); pf4(); pf5(); pf6(); + // CHECK: call x86_fastcallcc void %{{.*}}() + // CHECK: call x86_stdcallcc void %{{.*}}() + // CHECK: call x86_thiscallcc void %{{.*}}() + // CHECK: call x86_fastcallcc void %{{.*}}() + // CHECK: call x86_stdcallcc void %{{.*}}() + // CHECK: call x86_thiscallcc void %{{.*}}() + return 0; +} + +// PR7117 +void __stdcall f7(foo) int foo; {} +void f8(void) { + f7(0); + // CHECK: call x86_stdcallcc void (...)* bitcast +} diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c index bea6df39f965..6f3b00328771 100644 --- a/test/CodeGen/stdcall-fastcall.c +++ b/test/CodeGen/stdcall-fastcall.c @@ -2,32 +2,49 @@ void __attribute__((fastcall)) f1(void); void __attribute__((stdcall)) f2(void); -void __attribute__((fastcall)) f3(void) { -// CHECK: define x86_fastcallcc void @f3() +void __attribute__((thiscall)) f3(void); +void __attribute__((fastcall)) f4(void) { +// CHECK: define x86_fastcallcc void @f4() f1(); // CHECK: call x86_fastcallcc void @f1() } -void __attribute__((stdcall)) f4(void) { -// CHECK: define x86_stdcallcc void @f4() +void __attribute__((stdcall)) f5(void) { +// CHECK: define x86_stdcallcc void @f5() f2(); // CHECK: call x86_stdcallcc void @f2() } +void __attribute__((thiscall)) f6(void) { +// CHECK: define x86_thiscallcc void @f6() + f3(); +// CHECK: call x86_thiscallcc void @f3() +} // PR5280 void (__attribute__((fastcall)) *pf1)(void) = f1; void (__attribute__((stdcall)) *pf2)(void) = f2; -void (__attribute__((fastcall)) *pf3)(void) = f3; -void (__attribute__((stdcall)) *pf4)(void) = f4; +void (__attribute__((thiscall)) *pf3)(void) = f3; +void (__attribute__((fastcall)) *pf4)(void) = f4; +void (__attribute__((stdcall)) *pf5)(void) = f5; +void (__attribute__((thiscall)) *pf6)(void) = f6; int main(void) { - f3(); f4(); - // CHECK: call x86_fastcallcc void @f3() - // CHECK: call x86_stdcallcc void @f4() - pf1(); pf2(); pf3(); pf4(); + f4(); f5(); f6(); + // CHECK: call x86_fastcallcc void @f4() + // CHECK: call x86_stdcallcc void @f5() + // CHECK: call x86_thiscallcc void @f6() + pf1(); pf2(); pf3(); pf4(); pf5(); pf6(); // CHECK: call x86_fastcallcc void %{{.*}}() // CHECK: call x86_stdcallcc void %{{.*}}() + // CHECK: call x86_thiscallcc void %{{.*}}() // CHECK: call x86_fastcallcc void %{{.*}}() // CHECK: call x86_stdcallcc void %{{.*}}() + // CHECK: call x86_thiscallcc void %{{.*}}() return 0; } +// PR7117 +void __attribute((stdcall)) f7(foo) int foo; {} +void f8(void) { + f7(0); + // CHECK: call x86_stdcallcc void (...)* bitcast +} diff --git a/test/CodeGenCXX/PR5863-unreachable-block.cpp b/test/CodeGenCXX/PR5863-unreachable-block.cpp new file mode 100644 index 000000000000..77096153992b --- /dev/null +++ b/test/CodeGenCXX/PR5863-unreachable-block.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-llvm-only %s + +// PR5863 +class E { }; + +void P1() { + try { + int a=0, b=0; + if (a > b) // simply filling in 0 or 1 doesn't trigger the assertion + throw E(); // commenting out 'if' or 'throw' 'fixes' the assertion failure + try { } catch (...) { } // empty try/catch block needed for failure + } catch (...) { } // this try/catch block needed for failure +} diff --git a/test/CodeGenCXX/PR6747.cpp b/test/CodeGenCXX/PR6747.cpp deleted file mode 100644 index 5a07ce622013..000000000000 --- a/test/CodeGenCXX/PR6747.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s - -struct foo { - virtual void bar(); -// CHECK: define available_externally void @_ZN3foo3bazEv - virtual void baz() {} -}; -void zed() { - foo b; - b.baz(); -} diff --git a/test/CodeGenCXX/anonymous-namespaces.cpp b/test/CodeGenCXX/anonymous-namespaces.cpp index 695f8f59defc..fb3470ca9bee 100644 --- a/test/CodeGenCXX/anonymous-namespaces.cpp +++ b/test/CodeGenCXX/anonymous-namespaces.cpp @@ -1,6 +1,5 @@ // RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s - int f(); namespace { @@ -20,6 +19,13 @@ namespace { int D::d = f(); + // Check for generation of a VTT with internal linkage + // CHECK: @_ZTSN12_GLOBAL__N_11X1EE = internal constant + struct X { + struct EBase { }; + struct E : public virtual EBase { virtual ~E() {} }; + }; + // CHECK: define internal i32 @_ZN12_GLOBAL__N_13fooEv() int foo() { return 32; @@ -36,3 +42,5 @@ namespace { int concrete() { return a + foo() + A::foo(); } + +void test_XE() { throw X::E(); } diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp index adb395021e73..a4da2c04fd7b 100644 --- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp +++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp @@ -34,3 +34,47 @@ namespace PR7021 { // CHECK: ret void } } + +namespace test2 { + struct A { + struct { + union { + int b; + }; + }; + + A(); + }; + + A::A() : b(10) { } + // CHECK: define void @_ZN5test21AC2Ev( + // CHECK-NOT: } + // CHECK: store i32 10 + // CHECK: } +} + +namespace test3 { + struct A { + union { + mutable char fibers[100]; + struct { + void (*callback)(void*); + void *callback_value; + }; + }; + + A(); + }; + + A::A() : callback(0), callback_value(0) {} + // CHECK: define void @ZN5test31AC2Ev( + // CHECK: [[THIS:%.*]] = load + // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 + // CHECK-NEXT: [[STRUCT:%.*]] = getelementptr inbounds {{.*}} [[UNION]], i32 0, i32 0 + // CHECK-NEXT: [[CALLBACK:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0 + // CHECK-NEXT: store void (i8*)* null, void (i8*)** [[CALLBACK]] + // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 + // CHECK-NEXT: [[STRUCT:%.*]] = getelementptr inbounds {{.*}} [[UNION]], i32 0, i32 0 + // CHECK-NEXT: [[CVALUE:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0 + // CHECK-NEXT: store i8* null, void i8** [[CVALUE]] +} diff --git a/test/CodeGenCXX/array-value-initialize.cpp b/test/CodeGenCXX/array-value-initialize.cpp index 5fe6c2022d8f..8a3d5ff8b6f5 100644 --- a/test/CodeGenCXX/array-value-initialize.cpp +++ b/test/CodeGenCXX/array-value-initialize.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -emit-llvm -o - %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s +// RUN: %clang_cc1 -triple i386-apple-darwin -emit-llvm -o - %s // PR5463 extern "C" int printf(...); @@ -21,8 +22,31 @@ struct Foo { S sbar_[5]; }; -int main(void) -{ +int test1(void) { Foo a; } +// PR7063 + + +struct Unit +{ + Unit() {} + Unit(const Unit& v) {} +}; + + +struct Stuff +{ + Unit leafPos[1]; +}; + + +int main() +{ + + Stuff a; + Stuff b = a; + + return 0; +}
\ No newline at end of file diff --git a/test/CodeGenCXX/c99-variable-length-array.cpp b/test/CodeGenCXX/c99-variable-length-array.cpp new file mode 100644 index 000000000000..66c14ff579f2 --- /dev/null +++ b/test/CodeGenCXX/c99-variable-length-array.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s +struct X { + X(); + ~X(); +}; + +struct Y { + Y(); + ~Y(); +}; + +// CHECK: define void @_Z1fiPPKc( +void f(int argc, const char* argv[]) { + // CHECK: call void @_ZN1XC1Ev + X x; + // CHECK: call i8* @llvm.stacksave( + const char *argv2[argc]; + // CHECK: call void @_ZN1YC1Ev + Y y; + for (int i = 0; i != argc; ++i) + argv2[i] = argv[i]; + + // CHECK: call void @_ZN1YD1Ev + // CHECK: call void @llvm.stackrestore + // CHECK: call void @_ZN1XD1Ev + // CHECK: ret void +} diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp index 31091c5f4543..9303bdaba8bc 100644 --- a/test/CodeGenCXX/class-layout.cpp +++ b/test/CodeGenCXX/class-layout.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s -// An extra byte shoudl be allocated for an empty class. +// An extra byte should be allocated for an empty class. // CHECK: %struct.A = type { i8 } struct A { } a; @@ -9,5 +9,5 @@ struct A { } a; struct B { void *a; int b; } b; // C should have a vtable pointer. -// CHECK: %struct.C = type { i8**, i32 } +// CHECK: %struct.C = type { i32 (...)**, i32 } struct C { virtual void f(); int a; } *c; diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp index e435408aa840..f5b43d2ef491 100644 --- a/test/CodeGenCXX/condition.cpp +++ b/test/CodeGenCXX/condition.cpp @@ -14,6 +14,7 @@ void h() { struct X { X(); + X(const X&); ~X(); operator bool(); }; @@ -23,6 +24,8 @@ struct Y { ~Y(); }; +X getX(); + void if_destruct(int z) { // Verify that the condition variable is destroyed at the end of the // "if" statement. @@ -44,6 +47,14 @@ void if_destruct(int z) { // CHECK: call void @_ZN1YD1Ev // CHECK: br // CHECK: call void @_ZN1XD1Ev + + // CHECK: call void @_Z4getXv + // CHECK: call zeroext i1 @_ZN1XcvbEv + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + if (getX()) { } + + // CHECK: ret } struct ConvertibleToInt { @@ -52,6 +63,8 @@ struct ConvertibleToInt { operator int(); }; +ConvertibleToInt getConvToInt(); + void switch_destruct(int z) { // CHECK: call void @_ZN16ConvertibleToIntC1Ev switch (ConvertibleToInt conv = ConvertibleToInt()) { @@ -59,52 +72,181 @@ void switch_destruct(int z) { break; default: - // CHECK: {{sw.default:|:3}} + // CHECK: {{sw.default:|:5}} // CHECK: store i32 19 z = 19; break; } - // CHECK: {{sw.epilog:|:5}} + // CHECK: {{sw.epilog:|:6}} // CHECK: call void @_ZN16ConvertibleToIntD1Ev // CHECK: store i32 20 z = 20; + + // CHECK: call void @_Z12getConvToIntv + // CHECK: call i32 @_ZN16ConvertibleToIntcviEv + // CHECK: call void @_ZN16ConvertibleToIntD1Ev + switch(getConvToInt()) { + case 0: + break; + } + // CHECK: store i32 27 + z = 27; + // CHECK: ret } int foo(); void while_destruct(int z) { // CHECK: define void @_Z14while_destructi - // CHECK: {{while.cond:|:2}} + // CHECK: {{while.cond:|:3}} while (X x = X()) { // CHECK: call void @_ZN1XC1Ev - // CHECK: {{while.body:|:4}} + // CHECK: {{while.body:|:5}} // CHECK: store i32 21 z = 21; - // CHECK: {{while.cleanup:|:5}} + // CHECK: {{while.cleanup:|:6}} // CHECK: call void @_ZN1XD1Ev } - // CHECK: {{while.end|:7}} + // CHECK: {{while.end|:8}} // CHECK: store i32 22 z = 22; + + // CHECK: call void @_Z4getXv + // CHECK: call zeroext i1 @_ZN1XcvbEv + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + while(getX()) { } + + // CHECK: store i32 25 + z = 25; + + // CHECK: ret } void for_destruct(int z) { // CHECK: define void @_Z12for_destruct // CHECK: call void @_ZN1YC1Ev for(Y y = Y(); X x = X(); ++z) - // CHECK: {{for.cond:|:2}} + // CHECK: {{for.cond:|:4}} // CHECK: call void @_ZN1XC1Ev - // CHECK: {{for.body:|:4}} + // CHECK: {{for.body:|:6}} // CHECK: store i32 23 z = 23; - // CHECK: {{for.inc:|:5}} - // CHECK: br label %{{for.cond.cleanup|8}} - // CHECK: {{for.cond.cleanup:|:8}} + // CHECK: {{for.inc:|:7}} + // CHECK: br label %{{for.cond.cleanup|10}} + // CHECK: {{for.cond.cleanup:|:10}} // CHECK: call void @_ZN1XD1Ev - // CHECK: {{for.end:|:10}} + // CHECK: {{for.end:|:12}} // CHECK: call void @_ZN1YD1Ev // CHECK: store i32 24 z = 24; + + // CHECK: call void @_Z4getXv + // CHECK: call zeroext i1 @_ZN1XcvbEv + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + // CHECK: call void @_Z4getXv + // CHECK: load + // CHECK: add + // CHECK: call void @_ZN1XD1Ev + int i = 0; + for(; getX(); getX(), ++i) { } + z = 26; + // CHECK: store i32 26 + // CHECK: ret } + +void do_destruct(int z) { + // CHECK: define void @_Z11do_destruct + do { + // CHECK: store i32 77 + z = 77; + // CHECK: call void @_Z4getXv + // CHECK: call zeroext i1 @_ZN1XcvbEv + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + } while (getX()); + // CHECK: store i32 99 + z = 99; + // CHECK: ret +} + +int f(X); + +template<typename T> +int instantiated(T x) { + int result; + + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + // CHECK: store i32 2 + // CHECK: br + // CHECK: store i32 3 + if (f(x)) { result = 2; } else { result = 3; } + + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + // CHECK: store i32 4 + // CHECK: br + while (f(x)) { result = 4; } + + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + // CHECK: store i32 6 + // CHECK: br + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: store i32 5 + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + for (; f(x); f(x), result = 5) { + result = 6; + } + + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: switch i32 + // CHECK: store i32 7 + // CHECK: store i32 8 + switch (f(x)) { + case 0: + result = 7; + break; + + case 1: + result = 8; + } + + // CHECK: store i32 9 + // CHECK: br + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + do { + result = 9; + } while (f(x)); + + // CHECK: store i32 10 + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call zeroext i1 @_ZN1XcvbEv + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + do { + result = 10; + } while (X(x)); + + // CHECK: ret i32 + return result; +} + +template int instantiated(X); diff --git a/test/CodeGenCXX/cxx-apple-kext.cpp b/test/CodeGenCXX/cxx-apple-kext.cpp index 8d67b53657af..4ba69069bedd 100644 --- a/test/CodeGenCXX/cxx-apple-kext.cpp +++ b/test/CodeGenCXX/cxx-apple-kext.cpp @@ -3,9 +3,9 @@ // RUN: %clang -ccc-host-triple x86_64-apple-darwin10 %s -fapple-kext -flto -S -o - |\ // RUN: FileCheck --check-prefix=CHECK-KEXT %s -// CHECK-NO-KEXT: @_ZTI3foo = {{.*}} @_ZTVN10__cxxabiv117 // CHECK-NO-KEXT-NOT: _GLOBAL__D_a // CHECK-NO-KEXT: @is_hosted = global +// CHECK-NO-KEXT: @_ZTI3foo = {{.*}} @_ZTVN10__cxxabiv117 // CHECK-NO-KEXT: call i32 @__cxa_atexit({{.*}} @_ZN3fooD1Ev // CHECK-NO-KEXT: declare i32 @__cxa_atexit diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index d40b174012ff..1442e3740393 100644 --- a/test/CodeGenCXX/destructors.cpp +++ b/test/CodeGenCXX/destructors.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - -mconstructor-aliases | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fexceptions | FileCheck %s // CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev // CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev @@ -6,6 +6,10 @@ // CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev // CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev +// CHECK: @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev +// CHECK: @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev + struct A { int a; @@ -147,3 +151,62 @@ namespace test2 { // CHECK: define void @_ZN5test21BD2Ev // CHECK: call void @_ZN5test21AD2Ev } + +// PR7142 +namespace test3 { + struct A { virtual ~A(); }; + struct B { virtual ~B(); }; + namespace { // internal linkage => deferred + struct C : A, B {}; // ~B() in D requires a this-adjustment thunk + struct D : C {}; // D::~D() is an alias to C::~C() + } + + void test() { + new D; // Force emission of D's vtable + } + + // Checked at top of file: + // @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev + + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev( + // CHECK: call void @_ZN5test31BD2Ev( + // CHECK: call void @_ZN5test31AD2Ev( + // CHECK: ret void + + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev( + // CHECK: call void @_ZN5test312_GLOBAL__N_11DD1Ev( + // CHECK: call void @_ZdlPv( + // CHECK: ret void + + // Checked at top of file: + // @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev + // @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev + + // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11DD1Ev( + // CHECK: ret void + + // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11DD0Ev( + // CHECK: ret void + + // CHECK: declare void @_ZN5test31BD2Ev( + // CHECK: declare void @_ZN5test31AD2Ev( + + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev( + // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev( + // CHECK: call void @_ZdlPv( + // CHECK: ret void + + // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev( + // CHECK: ret void + + // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev( + // CHECK: ret void +} diff --git a/test/CodeGenCXX/dynamic-cast.cpp b/test/CodeGenCXX/dynamic-cast.cpp index aeb2a64157b4..9838e25b1d3f 100644 --- a/test/CodeGenCXX/dynamic-cast.cpp +++ b/test/CodeGenCXX/dynamic-cast.cpp @@ -1,8 +1,17 @@ -// RUN: %clang_cc1 %s -emit-llvm-only - +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -o - | FileCheck %s struct A { virtual void f(); }; struct B : A { }; +// CHECK: {{define.*@_Z1fP1A}} +B fail; const B& f(A *a) { - return dynamic_cast<const B&>(*a); + try { + // CHECK: call i8* @__dynamic_cast + // CHECK: br i1 + // CHECK: invoke void @__cxa_bad_cast() noreturn + dynamic_cast<const B&>(*a); + } catch (...) { + // CHECK: call i8* @llvm.eh.exception + } + return fail; } diff --git a/test/CodeGenCXX/dyncast.cpp b/test/CodeGenCXX/dyncast.cpp index 127cdd89683d..906d44b3c5ec 100644 --- a/test/CodeGenCXX/dyncast.cpp +++ b/test/CodeGenCXX/dyncast.cpp @@ -20,8 +20,6 @@ extern "C" int printf(const char *str...); void test1() { test1_B* bp = (test1_B*)&test1_d; test1_A* ap = &test1_d; - // This throws - // test1_D& dr = dynamic_cast<D&>(*bp); test1_D* dp = dynamic_cast<test1_D*>(bp); S(dp == 0, 1); ap = dynamic_cast<test1_A*>(bp); diff --git a/test/CodeGenCXX/implicit-copy-constructor.cpp b/test/CodeGenCXX/implicit-copy-constructor.cpp new file mode 100644 index 000000000000..a343dd154cd9 --- /dev/null +++ b/test/CodeGenCXX/implicit-copy-constructor.cpp @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +struct A { + A(); + A(const A&); + A(A&); + ~A(); +}; + +struct B { + B(); + B(B&); +}; + +struct C { + C() {} + C(C& other, A a = A()); + int i, j; +}; + +struct POD { + int array[3][4]; +}; + +struct D : A, B, virtual C { + D(); + int scalar; + int scalar_array[2][3]; + B class_member; + C class_member_array[2][3]; + POD pod_array[2][3]; + + union { + int x; + float f[3]; + }; +}; + +void f(D d) { + D d2(d); +} + +// CHECK: define linkonce_odr void @_ZN1DC1ERS_ +// CHECK: call void @_ZN1AC1Ev +// CHECK: call void @_ZN1CC2ERS_1A +// CHECK: call void @_ZN1AD1Ev +// CHECK: call void @_ZN1AC2ERS_ +// CHECK: call void @_ZN1BC2ERS_ +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}} +// CHECK: call void @_ZN1BC1ERS_ +// CHECK: br +// CHECK: {{icmp ult.*, 2}} +// CHECK: {{icmp ult.*, 3}} +// CHECK: call void @_ZN1AC1Ev +// CHECK: call void @_ZN1CC1ERS_1A +// CHECK: call void @_ZN1AD1Ev +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 288}} +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}} +// CHECK: ret void + + +template<class T> struct X0 { void f0(T * ) { } }; +template <class > struct X1 { X1( X1& , int = 0 ) { } }; +struct X2 { X1<int> result; }; +void test_X2() +{ + typedef X2 impl; + typedef X0<impl> pimpl; + impl* i; + pimpl pdata; + pdata.f0( new impl(*i)); +} diff --git a/test/CodeGenCXX/key-function-vtable.cpp b/test/CodeGenCXX/key-function-vtable.cpp index 251a14e28f2a..1cfeb0c5022d 100644 --- a/test/CodeGenCXX/key-function-vtable.cpp +++ b/test/CodeGenCXX/key-function-vtable.cpp @@ -32,11 +32,20 @@ namespace { } testg *testgvar = new testg; +struct X0 { virtual ~X0(); }; +struct X1 : X0 { + virtual void f(); +}; + +inline void X1::f() { } + +void use_X1(X1 *x1) { x1->f(); } + // FIXME: The checks are extremely difficult to get right when the globals // aren't alphabetized +// CHECK: @_ZTV2X1 = weak_odr constant // CHECK: @_ZTV5testa = constant [3 x i8*] [i8* null // CHECK: @_ZTV5testc = weak_odr constant [3 x i8*] [i8* null // CHECK: @_ZTVN12_GLOBAL__N_15testgE = internal constant [3 x i8*] [i8* null // CHECK: @_ZTV5teste = weak_odr constant [3 x i8*] [i8* null // CHECK: @_ZTV5testb = weak_odr constant [3 x i8*] [i8* null - diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp index 062610bd74a6..4c15eaac8835 100644 --- a/test/CodeGenCXX/mangle-subst-std.cpp +++ b/test/CodeGenCXX/mangle-subst-std.cpp @@ -1,5 +1,16 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s +// Check mangling of Vtables, VTTs, and construction vtables that +// involve standard substitutions. + +// CHECK: @_ZTVSd = weak_odr constant +// CHECK: @_ZTCSd0_Si = internal constant +// CHECK: @_ZTCSd16_So = internal constant +// CHECK: @_ZTTSd = weak_odr constant +// CHECK: @_ZTVSo = weak_odr constant +// CHECK: @_ZTTSo = weak_odr constant +// CHECK: @_ZTVSi = weak_odr constant +// CHECK: @_ZTTSi = weak_odr constant namespace std { struct A { A(); }; @@ -32,9 +43,30 @@ namespace std { void f(std::string) { } namespace std { - template<typename, typename> struct basic_istream { }; - template<typename, typename> struct basic_ostream { }; - template<typename, typename> struct basic_iostream { }; + template<typename, typename> struct basic_ios { + basic_ios(int); + virtual ~basic_ios(); + }; + template<typename charT, typename traits = char_traits<charT> > + struct basic_istream : virtual public basic_ios<charT, traits> { + basic_istream(int x) : basic_ios<charT, traits>(x), stored(x) { } + + int stored; + }; + template<typename charT, typename traits = char_traits<charT> > + struct basic_ostream : virtual public basic_ios<charT, traits> { + basic_ostream(int x) : basic_ios<charT, traits>(x), stored(x) { } + + float stored; + }; + + template<typename charT, typename traits = char_traits<charT> > + struct basic_iostream : public basic_istream<charT, traits>, + public basic_ostream<charT, traits> { + basic_iostream(int x) : basic_istream<charT, traits>(x), + basic_ostream<charT, traits>(x), + basic_ios<charT, traits>(x) { } + }; } // CHECK: _Z1fSi @@ -61,3 +93,9 @@ namespace std template<typename, typename, typename> struct basic_string { }; typedef basic_string<char, std::char_traits<char>, std::allocator<char> > not_string; void f(not_string) { } + +// Manglings for instantiations caused by this function are at the +// top of the test. +void create_streams() { + std::basic_iostream<char> bio(17); +} diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp new file mode 100644 index 000000000000..9ee553673f18 --- /dev/null +++ b/test/CodeGenCXX/nrvo.cpp @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -emit-llvm -O1 -o - %s | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s + +// Test code generation for the named return value optimization. +class X { +public: + X(); + X(const X&); + ~X(); +}; + +// CHECK: define void @_Z5test0v +// CHECK-EH: define void @_Z5test0v +X test0() { + X x; + // CHECK-NOT: call void @_ZN1XD1Ev + // CHECK: ret void + // CHECK-EH: br label + // CHECK-EH: call void @_ZN1XD1Ev + // CHECK-EH: br label + // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: ret void + return x; +} + +// CHECK: define void @_Z5test1b( +X test1(bool B) { + // CHECK: call void @_ZN1XC1Ev + X x; + // CHECK-NOT: call void @_ZN1XD1Ev + // CHECK: ret void + if (B) + return (x); + return x; + // CHECK-EH: invoke void @_ZN1XD1Ev +} + +// CHECK: define void @_Z5test2b +// CHECK-EH: define void @_Z5test2b +X test2(bool B) { + // No NRVO + // CHECK: call void @_ZN1XC1Ev + X x; + // CHECK: call void @_ZN1XC1Ev + X y; + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK-EH: invoke void @_ZN1XC1ERKS_ + if (B) + return y; + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK-EH: invoke void @_ZN1XC1ERKS_ + return x; + // CHECK: call void @_ZN1XD1Ev + // CHECK: call void @_ZN1XD1Ev + // CHECK: ret void + // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: invoke void @_ZN1XD1Ev +} + +X test3(bool B) { + // FIXME: We don't manage to apply NRVO here, although we could. + { + X y; + return y; + } + X x; + return x; +} + +extern "C" void exit(int) throw(); + +// CHECK: define void @_Z5test4b +X test4(bool B) { + { + // CHECK: tail call void @_ZN1XC1Ev + X x; + // CHECK: br i1 + if (B) + return x; + } + // CHECK: tail call void @_ZN1XD1Ev + // CHECK: tail call void @exit(i32 1) + exit(1); +} diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp index d96eb03b8d82..affe1f7d18de 100644 --- a/test/CodeGenCXX/pointers-to-data-members.cpp +++ b/test/CodeGenCXX/pointers-to-data-members.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 | FileCheck %s - +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 -O3 | FileCheck --check-prefix=CHECK-O3 %s struct A { int a; int b; }; struct B { int b; }; struct C : B, A { }; @@ -35,6 +35,21 @@ namespace ZeroInit { int A::*pa; } s; } ss; + + struct A { + int A::*a; + int b; + }; + + struct B { + A a[10]; + char c; + int B::*b; + }; + + struct C : A, B { int j; }; + // CHECK: @_ZN8ZeroInit1cE = global %"struct.ZeroInit::C" { [16 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00", [176 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i32 0, [4 x i8] zeroinitializer } + C c; } // PR5674 @@ -85,3 +100,54 @@ namespace Comparisons { if (0 == a) { } } } + +namespace ValueInit { + +struct A { + int A::*a; + + char c; + + A(); +}; + +// CHECK: define void @_ZN9ValueInit1AC2Ev +// CHECK: store i64 -1, i64* +// CHECK: ret void +A::A() : a() {} + +} + +namespace PR7139 { + +struct pair { + int first; + int second; +}; + +typedef int pair::*ptr_to_member_type; + +struct ptr_to_member_struct { + ptr_to_member_type data; + int i; +}; + +struct A { + ptr_to_member_struct a; + + A() : a() {} +}; + +// CHECK-O3: define zeroext i1 @_ZN6PR71395checkEv() nounwind readnone +bool check() { + // CHECK-O3: ret i1 true + return A().a.data == 0; +} + +// CHECK-O3: define zeroext i1 @_ZN6PR71396check2Ev() nounwind readnone +bool check2() { + // CHECK-O3: ret i1 true + return ptr_to_member_type() == 0; +} + +} diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp index 5a5947dd8162..6fc610298bd2 100644 --- a/test/CodeGenCXX/references.cpp +++ b/test/CodeGenCXX/references.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -emit-llvm -o - %s | FileCheck %s void t1() { extern int& a; int b = a; @@ -155,3 +155,73 @@ void f0(s1 a) { s1 b = a; } // CHECK: load // CHECK: ret const int &f2() { return 0; } + +// Don't constant fold const reference parameters with default arguments to +// their default arguments. +namespace N1 { + const int foo = 1; + // CHECK: @_ZN2N14test + int test(const int& arg = foo) { + // Ensure this array is on the stack where we can set values instead of + // being a global constant. + // CHECK: %args_array = alloca + const int* const args_array[] = { &arg }; + } +} + +// Bind to subobjects while extending the life of the complete object. +namespace N2 { + class X { + public: + X(const X&); + X &operator=(const X&); + ~X(); + }; + + struct P { + X first; + }; + + P getP(); + + // CHECK: define void @_ZN2N21fEi + // CHECK: call void @_ZN2N24getPEv + // CHECK: getelementptr inbounds + // CHECK: store i32 17 + // CHECK: call void @_ZN2N21PD1Ev + void f(int i) { + const X& xr = getP().first; + i = 17; + } + + struct SpaceWaster { + int i, j; + }; + + struct ReallyHasX { + X x; + }; + + struct HasX : ReallyHasX { }; + + struct HasXContainer { + HasX has; + }; + + struct Y : SpaceWaster, HasXContainer { }; + struct Z : SpaceWaster, Y { }; + + Z getZ(); + + // CHECK: define void @_ZN2N21gEi + // CHECK: call void @_ZN2N24getZEv + // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK: store i32 19 + // CHECK: call void @_ZN2N21ZD1Ev + // CHECK: ret void + void g(int i) { + const X &xr = getZ().has.x; + i = 19; + } +} diff --git a/test/CodeGenCXX/rtti-linkage.cpp b/test/CodeGenCXX/rtti-linkage.cpp index b9eb5b4ad411..9d85a2c69ba0 100644 --- a/test/CodeGenCXX/rtti-linkage.cpp +++ b/test/CodeGenCXX/rtti-linkage.cpp @@ -1,47 +1,53 @@ -// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | sort | FileCheck %s + +// FIXME: Fails on Win32, dunno why. +// XFAIL: win32 + #include <typeinfo> -// CHECK: _ZTS1B = constant -// CHECK: _ZTS1A = weak_odr constant + + +// CHECK: _ZTIN12_GLOBAL__N_11DE to + + + // CHECK: _ZTI1A = weak_odr constant // CHECK: _ZTI1B = constant -// CHECK: _ZTSP1C = internal constant -// CHECK: _ZTS1C = internal constant // CHECK: _ZTI1C = internal constant -// CHECK: _ZTIP1C = internal constant -// CHECK: _ZTSPP1C = internal constant -// CHECK: _ZTIPP1C = internal constant -// CHECK: _ZTSM1Ci = internal constant -// CHECK: _ZTIM1Ci = internal constant -// CHECK: _ZTSPM1Ci = internal constant -// CHECK: _ZTIPM1Ci = internal constant -// CHECK: _ZTSM1CS_ = internal constant -// CHECK: _ZTIM1CS_ = internal constant -// CHECK: _ZTSM1CPS_ = internal constant -// CHECK: _ZTIM1CPS_ = internal constant -// CHECK: _ZTSM1A1C = internal constant +// CHECK: _ZTIFN12_GLOBAL__N_11DEvE = internal constant +// CHECK: _ZTIFvN12_GLOBAL__N_11DEE = internal constant +// CHECK: _ZTIFvvE = weak_odr // CHECK: _ZTIM1A1C = internal constant -// CHECK: _ZTSM1AP1C = internal constant // CHECK: _ZTIM1AP1C = internal constant - -// CHECK: _ZTS1F = weak_odr constant - -// CHECK: _ZTSN12_GLOBAL__N_11DE = internal constant +// CHECK: _ZTIM1CPS_ = internal constant +// CHECK: _ZTIM1CS_ = internal constant +// CHECK: _ZTIM1Ci = internal constant // CHECK: _ZTIN12_GLOBAL__N_11DE = internal constant -// CHECK: _ZTSPN12_GLOBAL__N_11DE = internal constant +// CHECK: _ZTIN12_GLOBAL__N_11EE = internal constant +// CHECK: _ZTIP1C = internal constant +// CHECK: _ZTIPFvvE = weak_odr constant +// CHECK: _ZTIPM1Ci = internal constant // CHECK: _ZTIPN12_GLOBAL__N_11DE = internal constant +// CHECK: _ZTIPP1C = internal constant +// CHECK: _ZTS1A = weak_odr constant +// CHECK: _ZTS1B = constant +// CHECK: _ZTS1C = internal constant +// CHECK: _ZTS1F = weak_odr constant // CHECK: _ZTSFN12_GLOBAL__N_11DEvE = internal constant -// CHECK: _ZTIFN12_GLOBAL__N_11DEvE = internal constant // CHECK: _ZTSFvN12_GLOBAL__N_11DEE = internal constant -// CHECK: _ZTIFvN12_GLOBAL__N_11DEE = internal constant - -// CHECK: _ZTSPFvvE = weak_odr constant // CHECK: _ZTSFvvE = weak_odr constant -// CHECK: _ZTIFvvE = weak_odr -// CHECK: _ZTIPFvvE = weak_odr constant - +// CHECK: _ZTSM1A1C = internal constant +// CHECK: _ZTSM1AP1C = internal constant +// CHECK: _ZTSM1CPS_ = internal constant +// CHECK: _ZTSM1CS_ = internal constant +// CHECK: _ZTSM1Ci = internal constant +// CHECK: _ZTSN12_GLOBAL__N_11DE = internal constant // CHECK: _ZTSN12_GLOBAL__N_11EE = internal constant -// CHECK: _ZTIN12_GLOBAL__N_11EE = internal constant +// CHECK: _ZTSP1C = internal constant +// CHECK: _ZTSPFvvE = weak_odr constant +// CHECK: _ZTSPM1Ci = internal constant +// CHECK: _ZTSPN12_GLOBAL__N_11DE = internal constant +// CHECK: _ZTSPP1C = internal constant // A has no key function, so its RTTI data should be weak_odr. struct A { }; @@ -99,6 +105,5 @@ const std::type_info &t2() { (void)typeid(E); - // CHECK: _ZTIN12_GLOBAL__N_11DE to return typeid(getD()); } diff --git a/test/CodeGenCXX/static-init-3.cpp b/test/CodeGenCXX/static-init-3.cpp new file mode 100644 index 000000000000..5bf76a61708e --- /dev/null +++ b/test/CodeGenCXX/static-init-3.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s + +// PR7050 +template<class T> struct X0 : public T { }; + +template <class T> +struct X1 +{ + static T & instance; + // include this to provoke instantiation at pre-execution time + static void use(T const &) {} + static T & get() { + static X0<T> t; + use(instance); + return static_cast<T &>(t); + } +}; + +// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak global %struct.X0* null, align 8 +// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak global %struct.X0* null, align 8 +template<class T> T & X1<T>::instance = X1<T>::get(); + +class A { }; +class B : public A { }; + +template<typename T> struct X2 {}; +X2< B > bg = X1< X2< B > >::get(); +X2< A > ag = X1< X2< A > >::get(); diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp index 750da02603b3..9ad87df8f0c3 100644 --- a/test/CodeGenCXX/static-init.cpp +++ b/test/CodeGenCXX/static-init.cpp @@ -2,8 +2,9 @@ // CHECK: @_ZZ1hvE1i = internal global i32 0, align 4 -// CHECK: @_ZZ2h2vE1i = weak global i32 0 -// CHECK: @_ZGVZ2h2vE1i = weak global i64 0 +// CHECK: @_ZZN5test16getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 4 +// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0 +// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0 struct A { A(); @@ -11,7 +12,9 @@ struct A { }; void f() { - // CHECK: call void @_ZN1AC1Ev( + // CHECK: call i32 @__cxa_guard_acquire + // CHECK: call void @_ZN1AC1Ev + // CHECK: call void @__cxa_guard_release // CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) static A a; } @@ -45,3 +48,13 @@ namespace test0 { static A r; } } + +namespace test1 { + // CHECK: define internal i32 @_ZN5test16getvarEi( + static inline int getvar(int index) { + static const int var[] = { 1, 0, 2, 4 }; + return var[index]; + } + + void test() { (void) getvar(2); } +} diff --git a/test/CodeGenCXX/static-local-in-local-class.cpp b/test/CodeGenCXX/static-local-in-local-class.cpp index d9e044ce9d97..ebf560ab9805 100644 --- a/test/CodeGenCXX/static-local-in-local-class.cpp +++ b/test/CodeGenCXX/static-local-in-local-class.cpp @@ -19,3 +19,15 @@ void X::f() { } (void)i; } + +// pr7101 +void foo() { + static int n = 0; + struct Helper { + static void Execute() { + n++; + } + }; + Helper::Execute(); +} + diff --git a/test/CodeGenCXX/template-linkage.cpp b/test/CodeGenCXX/template-linkage.cpp index ccd61a7bbe30..63a5c09cd7d8 100644 --- a/test/CodeGenCXX/template-linkage.cpp +++ b/test/CodeGenCXX/template-linkage.cpp @@ -22,3 +22,23 @@ template void f<int>(int); template <typename T> inline void g(T) { } template void g<int>(int); +template<typename T> +struct X0 { + virtual ~X0() { } +}; + +template<typename T> +struct X1 : X0<T> { + virtual void blarg(); +}; + +template<typename T> void X1<T>::blarg() { } + +extern template struct X0<char>; +extern template struct X1<char>; + +// CHECK: define linkonce_odr void @_ZN2X1IcED1Ev( +void test_X1() { + X1<char> i1c; +} + diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp new file mode 100644 index 000000000000..9347cc9616a1 --- /dev/null +++ b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -emit-llvm -o - -fexceptions -triple x86_64-apple-darwin10 %s | FileCheck %s + +struct X { + X(); + ~X(); +}; + +struct Y { }; + +// CHECK: define void @_Z1fv +void f() { + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x) + // CHECK: invoke void @_ZN1XC1Ev + // CHECK: call void @__cxa_guard_release(i64* @_ZGVZ1fvE1x) + // CHECK: call i32 @__cxa_atexit + // CHECK: br + static X x; + // CHECK: call i8* @llvm.eh.exception() + // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector + // CHECK: call void @__cxa_guard_abort(i64* @_ZGVZ1fvE1x) + // CHECK: call void @_Unwind_Resume_or_Rethrow + // CHECK: unreachable + + // CHECK: call i8* @__cxa_allocate_exception + throw Y(); +} diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp index b91ba3239b1e..79ca709f470d 100644 --- a/test/CodeGenCXX/thunks.cpp +++ b/test/CodeGenCXX/thunks.cpp @@ -86,9 +86,6 @@ void C::f() { } } -// This is from Test5: -// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv - // Check that the thunk gets internal linkage. namespace { @@ -106,7 +103,6 @@ struct C : A, B { virtual void f(); }; -// CHECK: define internal void @_ZThn8_N12_GLOBAL__N_11C1fEv( void C::f() { } } @@ -134,4 +130,112 @@ void f(B b) { } } +namespace Test6 { + struct X { + X(); + X(const X&); + X &operator=(const X&); + ~X(); + }; + + struct P { + P(); + P(const P&); + ~P(); + X first; + X second; + }; + + P getP(); + + struct Base1 { + int i; + + virtual X f() { return X(); } + }; + + struct Base2 { + float real; + + virtual X f() { return X(); } + }; + + struct Thunks : Base1, Base2 { + long l; + + virtual X f(); + }; + + // CHECK: define void @_ZThn16_N5Test66Thunks1fEv + // CHECK-NOT: memcpy + // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret}} + // CHECK: ret void + X Thunks::f() { return X(); } +} + +namespace Test7 { + // PR7188 + struct X { + X(); + X(const X&); + X &operator=(const X&); + ~X(); + }; + + struct Small { short s; }; + struct Large { + char array[1024]; + }; + + class A { + protected: + virtual void foo() = 0; + }; + + class B : public A { + protected: + virtual void bar() = 0; + }; + + class C : public A { + protected: + virtual void baz(X, X&, _Complex float, Small, Small&, Large) = 0; + }; + + class D : public B, + public C { + + void foo() {} + void bar() {} + void baz(X, X&, _Complex float, Small, Small&, Large); + }; + + void D::baz(X, X&, _Complex float, Small, Small&, Large) { } + + // CHECK: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE( + // CHECK-NOT: memcpy + // CHECK: ret void + void testD() { D d; } +} + +namespace Test8 { + struct NonPOD { ~NonPOD(); int x, y, z; }; + struct A { virtual void foo(); }; + struct B { virtual void bar(NonPOD); }; + struct C : A, B { virtual void bar(NonPOD); static void helper(NonPOD); }; + + // CHECK: define void @_ZN5Test81C6helperENS_6NonPODE([[NONPODTYPE:%.*]]* + void C::helper(NonPOD var) {} + + // CHECK: define void @_ZThn8_N5Test81C3barENS_6NonPODE( + // CHECK-NOT: load [[NONPODTYPE]]* + // CHECK-NOT: memcpy + // CHECK: ret void + void C::bar(NonPOD var) {} +} + +/**** The following has to go at the end of the file ****/ +// This is from Test5: +// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv +// CHECK: define internal void @_ZThn8_N12_GLOBAL__N_11C1fEv( diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp index 7de9dd2a6085..22c49a089d0d 100644 --- a/test/CodeGenCXX/virtual-base-destructor-call.cpp +++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -49,3 +49,4 @@ int main() { // CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev // CHECK-NOT: call // CHECK: } + diff --git a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp index 50e04357b390..991c2bc7220f 100644 --- a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp +++ b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp @@ -9,6 +9,7 @@ struct B { void B::f() { } +// CHECK: define i64 @_ZN1D1gEv(%struct.B* %this) // CHECK: declare void @_ZN1B1gEv() struct C; @@ -24,7 +25,6 @@ struct C { int a; }; -// CHECK: define i64 @_ZN1D1gEv(%struct.B* %this) C D::g() { return C(); } diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp index f2f5179d4a19..60b46fec39b3 100644 --- a/test/CodeGenCXX/vtable-layout.cpp +++ b/test/CodeGenCXX/vtable-layout.cpp @@ -1,4 +1,46 @@ -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t 2>&1 +// RUN: FileCheck --check-prefix=CHECK-1 %s < %t +// RUN: FileCheck --check-prefix=CHECK-2 %s < %t +// RUN: FileCheck --check-prefix=CHECK-3 %s < %t +// RUN: FileCheck --check-prefix=CHECK-4 %s < %t +// RUN: FileCheck --check-prefix=CHECK-5 %s < %t +// RUN: FileCheck --check-prefix=CHECK-6 %s < %t +// RUN: FileCheck --check-prefix=CHECK-7 %s < %t +// RUN: FileCheck --check-prefix=CHECK-8 %s < %t +// RUN: FileCheck --check-prefix=CHECK-9 %s < %t +// RUN: FileCheck --check-prefix=CHECK-10 %s < %t +// RUN: FileCheck --check-prefix=CHECK-11 %s < %t +// RUN: FileCheck --check-prefix=CHECK-12 %s < %t +// RUN: FileCheck --check-prefix=CHECK-13 %s < %t +// RUN: FileCheck --check-prefix=CHECK-14 %s < %t +// RUN: FileCheck --check-prefix=CHECK-15 %s < %t +// RUN: FileCheck --check-prefix=CHECK-16 %s < %t +// RUN: FileCheck --check-prefix=CHECK-17 %s < %t +// RUN: FileCheck --check-prefix=CHECK-18 %s < %t +// RUN: FileCheck --check-prefix=CHECK-19 %s < %t +// RUN: FileCheck --check-prefix=CHECK-20 %s < %t +// RUN: FileCheck --check-prefix=CHECK-21 %s < %t +// RUN: FileCheck --check-prefix=CHECK-22 %s < %t +// RUN: FileCheck --check-prefix=CHECK-23 %s < %t +// RUN: FileCheck --check-prefix=CHECK-24 %s < %t +// RUN: FileCheck --check-prefix=CHECK-25 %s < %t +// RUN: FileCheck --check-prefix=CHECK-26 %s < %t +// RUN: FileCheck --check-prefix=CHECK-27 %s < %t +// RUN: FileCheck --check-prefix=CHECK-28 %s < %t +// RUN: FileCheck --check-prefix=CHECK-29 %s < %t +// RUN: FileCheck --check-prefix=CHECK-30 %s < %t +// RUN: FileCheck --check-prefix=CHECK-31 %s < %t +// RUN: FileCheck --check-prefix=CHECK-32 %s < %t +// RUN: FileCheck --check-prefix=CHECK-33 %s < %t +// RUN: FileCheck --check-prefix=CHECK-34 %s < %t +// RUN: FileCheck --check-prefix=CHECK-35 %s < %t +// RUN: FileCheck --check-prefix=CHECK-36 %s < %t +// RUN: FileCheck --check-prefix=CHECK-37 %s < %t +// RUN: FileCheck --check-prefix=CHECK-38 %s < %t +// RUN: FileCheck --check-prefix=CHECK-39 %s < %t +// RUN: FileCheck --check-prefix=CHECK-40 %s < %t +// RUN: FileCheck --check-prefix=CHECK-41 %s < %t +// RUN: FileCheck --check-prefix=CHECK-42 %s < %t // For now, just verify this doesn't crash. namespace test0 { @@ -11,11 +53,11 @@ namespace test0 { } namespace Test1 { -// CHECK: Vtable for 'Test1::A' (3 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test1::A RTTI -// CHECK-NEXT: -- (Test1::A, 0) vtable address -- -// CHECK-NEXT: 2 | void Test1::A::f() +// CHECK-1: Vtable for 'Test1::A' (3 entries). +// CHECK-1-NEXT: 0 | offset_to_top (0) +// CHECK-1-NEXT: 1 | Test1::A RTTI +// CHECK-1-NEXT: -- (Test1::A, 0) vtable address -- +// CHECK-1-NEXT: 2 | void Test1::A::f() struct A { virtual void f(); }; @@ -26,17 +68,17 @@ void A::f() { } namespace Test2 { // This is a smoke test of the vtable dumper. -// CHECK: Vtable for 'Test2::A' (9 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test2::A RTTI -// CHECK-NEXT: -- (Test2::A, 0) vtable address -- -// CHECK-NEXT: 2 | void Test2::A::f() -// CHECK-NEXT: 3 | void Test2::A::f() const -// CHECK-NEXT: 4 | Test2::A *Test2::A::g(int) -// CHECK-NEXT: 5 | Test2::A::~A() [complete] -// CHECK-NEXT: 6 | Test2::A::~A() [deleting] -// CHECK-NEXT: 7 | void Test2::A::h() -// CHECK-NEXT: 8 | Test2::A &Test2::A::operator=(Test2::A const &) +// CHECK-2: Vtable for 'Test2::A' (9 entries). +// CHECK-2-NEXT: 0 | offset_to_top (0) +// CHECK-2-NEXT: 1 | Test2::A RTTI +// CHECK-2-NEXT: -- (Test2::A, 0) vtable address -- +// CHECK-2-NEXT: 2 | void Test2::A::f() +// CHECK-2-NEXT: 3 | void Test2::A::f() const +// CHECK-2-NEXT: 4 | Test2::A *Test2::A::g(int) +// CHECK-2-NEXT: 5 | Test2::A::~A() [complete] +// CHECK-2-NEXT: 6 | Test2::A::~A() [deleting] +// CHECK-2-NEXT: 7 | void Test2::A::h() +// CHECK-2-NEXT: 8 | Test2::A &Test2::A::operator=(Test2::A const &) struct A { virtual void f(); virtual void f() const; @@ -50,14 +92,14 @@ void A::f() { } // Another simple vtable dumper test. -// CHECK: Vtable for 'Test2::B' (6 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test2::B RTTI -// CHECK-NEXT: -- (Test2::B, 0) vtable address -- -// CHECK-NEXT: 2 | void Test2::B::f() -// CHECK-NEXT: 3 | void Test2::B::g() [pure] -// CHECK-NEXT: 4 | Test2::B::~B() [complete] [pure] -// CHECK-NEXT: 5 | Test2::B::~B() [deleting] [pure] +// CHECK-3: Vtable for 'Test2::B' (6 entries). +// CHECK-3-NEXT: 0 | offset_to_top (0) +// CHECK-3-NEXT: 1 | Test2::B RTTI +// CHECK-3-NEXT: -- (Test2::B, 0) vtable address -- +// CHECK-3-NEXT: 2 | void Test2::B::f() +// CHECK-3-NEXT: 3 | void Test2::B::g() [pure] +// CHECK-3-NEXT: 4 | Test2::B::~B() [complete] [pure] +// CHECK-3-NEXT: 5 | Test2::B::~B() [deleting] [pure] struct B { virtual void f(); virtual void g() = 0; @@ -73,52 +115,52 @@ namespace Test3 { // then the function should not have an entry in the derived class (unless the return // value requires adjusting). -// CHECK: Vtable for 'Test3::A' (3 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test3::A RTTI -// CHECK-NEXT: -- (Test3::A, 0) vtable address -- -// CHECK-NEXT: 2 | void Test3::A::f() +// CHECK-4: Vtable for 'Test3::A' (3 entries). +// CHECK-4-NEXT: 0 | offset_to_top (0) +// CHECK-4-NEXT: 1 | Test3::A RTTI +// CHECK-4-NEXT: -- (Test3::A, 0) vtable address -- +// CHECK-4-NEXT: 2 | void Test3::A::f() struct A { virtual void f(); }; void A::f() { } -// CHECK: Vtable for 'Test3::B' (4 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test3::B RTTI -// CHECK-NEXT: -- (Test3::A, 0) vtable address -- -// CHECK-NEXT: -- (Test3::B, 0) vtable address -- -// CHECK-NEXT: 2 | void Test3::B::f() -// CHECK-NEXT: 3 | void Test3::B::g() +// CHECK-5: Vtable for 'Test3::B' (4 entries). +// CHECK-5-NEXT: 0 | offset_to_top (0) +// CHECK-5-NEXT: 1 | Test3::B RTTI +// CHECK-5-NEXT: -- (Test3::A, 0) vtable address -- +// CHECK-5-NEXT: -- (Test3::B, 0) vtable address -- +// CHECK-5-NEXT: 2 | void Test3::B::f() +// CHECK-5-NEXT: 3 | void Test3::B::g() struct B : A { virtual void f(); virtual void g(); }; void B::f() { } -// CHECK: Vtable for 'Test3::C' (5 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test3::C RTTI -// CHECK-NEXT: -- (Test3::A, 0) vtable address -- -// CHECK-NEXT: -- (Test3::C, 0) vtable address -- -// CHECK-NEXT: 2 | void Test3::A::f() -// CHECK-NEXT: 3 | void Test3::C::g() -// CHECK-NEXT: 4 | void Test3::C::h() +// CHECK-6: Vtable for 'Test3::C' (5 entries). +// CHECK-6-NEXT: 0 | offset_to_top (0) +// CHECK-6-NEXT: 1 | Test3::C RTTI +// CHECK-6-NEXT: -- (Test3::A, 0) vtable address -- +// CHECK-6-NEXT: -- (Test3::C, 0) vtable address -- +// CHECK-6-NEXT: 2 | void Test3::A::f() +// CHECK-6-NEXT: 3 | void Test3::C::g() +// CHECK-6-NEXT: 4 | void Test3::C::h() struct C : A { virtual void g(); virtual void h(); }; void C::g() { } -// CHECK: Vtable for 'Test3::D' (5 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test3::D RTTI -// CHECK-NEXT: -- (Test3::A, 0) vtable address -- -// CHECK-NEXT: -- (Test3::B, 0) vtable address -- -// CHECK-NEXT: -- (Test3::D, 0) vtable address -- -// CHECK-NEXT: 2 | void Test3::D::f() -// CHECK-NEXT: 3 | void Test3::D::g() -// CHECK-NEXT: 4 | void Test3::D::h() +// CHECK-7: Vtable for 'Test3::D' (5 entries). +// CHECK-7-NEXT: 0 | offset_to_top (0) +// CHECK-7-NEXT: 1 | Test3::D RTTI +// CHECK-7-NEXT: -- (Test3::A, 0) vtable address -- +// CHECK-7-NEXT: -- (Test3::B, 0) vtable address -- +// CHECK-7-NEXT: -- (Test3::D, 0) vtable address -- +// CHECK-7-NEXT: 2 | void Test3::D::f() +// CHECK-7-NEXT: 3 | void Test3::D::g() +// CHECK-7-NEXT: 4 | void Test3::D::h() struct D : B { virtual void f(); virtual void g(); @@ -140,14 +182,14 @@ struct A { virtual R2 *f(); }; -// CHECK: Vtable for 'Test4::B' (4 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test4::B RTTI -// CHECK-NEXT: -- (Test4::A, 0) vtable address -- -// CHECK-NEXT: -- (Test4::B, 0) vtable address -- -// CHECK-NEXT: 2 | Test4::R3 *Test4::B::f() -// CHECK-NEXT: [return adjustment: 4 non-virtual] -// CHECK-NEXT: 3 | Test4::R3 *Test4::B::f() +// CHECK-8: Vtable for 'Test4::B' (4 entries). +// CHECK-8-NEXT: 0 | offset_to_top (0) +// CHECK-8-NEXT: 1 | Test4::B RTTI +// CHECK-8-NEXT: -- (Test4::A, 0) vtable address -- +// CHECK-8-NEXT: -- (Test4::B, 0) vtable address -- +// CHECK-8-NEXT: 2 | Test4::R3 *Test4::B::f() +// CHECK-8-NEXT: [return adjustment: 4 non-virtual] +// CHECK-8-NEXT: 3 | Test4::R3 *Test4::B::f() struct B : A { virtual R3 *f(); @@ -162,14 +204,14 @@ struct C { virtual V1 *f(); }; -// CHECK: Vtable for 'Test4::D' (4 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test4::D RTTI -// CHECK-NEXT: -- (Test4::C, 0) vtable address -- -// CHECK-NEXT: -- (Test4::D, 0) vtable address -- -// CHECK-NEXT: 2 | Test4::V2 *Test4::D::f() -// CHECK-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset] -// CHECK-NEXT: 3 | Test4::V2 *Test4::D::f() +// CHECK-9: Vtable for 'Test4::D' (4 entries). +// CHECK-9-NEXT: 0 | offset_to_top (0) +// CHECK-9-NEXT: 1 | Test4::D RTTI +// CHECK-9-NEXT: -- (Test4::C, 0) vtable address -- +// CHECK-9-NEXT: -- (Test4::D, 0) vtable address -- +// CHECK-9-NEXT: 2 | Test4::V2 *Test4::D::f() +// CHECK-9-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset] +// CHECK-9-NEXT: 3 | Test4::V2 *Test4::D::f() struct D : C { virtual V2 *f(); }; @@ -178,14 +220,14 @@ V2 *D::f() { return 0; }; // Virtual result adjustments with an additional non-virtual adjustment. struct V3 : virtual R3 { int r3; }; -// CHECK: Vtable for 'Test4::E' (4 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test4::E RTTI -// CHECK-NEXT: -- (Test4::A, 0) vtable address -- -// CHECK-NEXT: -- (Test4::E, 0) vtable address -- -// CHECK-NEXT: 2 | Test4::V3 *Test4::E::f() -// CHECK-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset] -// CHECK-NEXT: 3 | Test4::V3 *Test4::E::f() +// CHECK-10: Vtable for 'Test4::E' (4 entries). +// CHECK-10-NEXT: 0 | offset_to_top (0) +// CHECK-10-NEXT: 1 | Test4::E RTTI +// CHECK-10-NEXT: -- (Test4::A, 0) vtable address -- +// CHECK-10-NEXT: -- (Test4::E, 0) vtable address -- +// CHECK-10-NEXT: 2 | Test4::V3 *Test4::E::f() +// CHECK-10-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset] +// CHECK-10-NEXT: 3 | Test4::V3 *Test4::E::f() struct E : A { virtual V3 *f(); @@ -194,14 +236,14 @@ V3 *E::f() { return 0;} // Test that a pure virtual member doesn't get a thunk. -// CHECK: Vtable for 'Test4::F' (5 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test4::F RTTI -// CHECK-NEXT: -- (Test4::A, 0) vtable address -- -// CHECK-NEXT: -- (Test4::F, 0) vtable address -- -// CHECK-NEXT: 2 | Test4::R3 *Test4::F::f() [pure] -// CHECK-NEXT: 3 | void Test4::F::g() -// CHECK-NEXT: 4 | Test4::R3 *Test4::F::f() [pure] +// CHECK-11: Vtable for 'Test4::F' (5 entries). +// CHECK-11-NEXT: 0 | offset_to_top (0) +// CHECK-11-NEXT: 1 | Test4::F RTTI +// CHECK-11-NEXT: -- (Test4::A, 0) vtable address -- +// CHECK-11-NEXT: -- (Test4::F, 0) vtable address -- +// CHECK-11-NEXT: 2 | Test4::R3 *Test4::F::f() [pure] +// CHECK-11-NEXT: 3 | void Test4::F::g() +// CHECK-11-NEXT: 4 | Test4::R3 *Test4::F::f() [pure] struct F : A { virtual void g(); virtual R3 *f() = 0; @@ -229,21 +271,21 @@ struct B2 : A { int b2; }; -// CHECK: Vtable for 'Test5::C' (9 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test5::C RTTI -// CHECK-NEXT: -- (Test5::A, 0) vtable address -- -// CHECK-NEXT: -- (Test5::B1, 0) vtable address -- -// CHECK-NEXT: -- (Test5::C, 0) vtable address -- -// CHECK-NEXT: 2 | void Test5::B1::f() -// CHECK-NEXT: 3 | void Test5::A::g() -// CHECK-NEXT: 4 | void Test5::C::h() -// CHECK-NEXT: 5 | offset_to_top (-16) -// CHECK-NEXT: 6 | Test5::C RTTI -// CHECK-NEXT: -- (Test5::A, 16) vtable address -- -// CHECK-NEXT: -- (Test5::B2, 16) vtable address -- -// CHECK-NEXT: 7 | void Test5::A::f() -// CHECK-NEXT: 8 | void Test5::B2::g() +// CHECK-12: Vtable for 'Test5::C' (9 entries). +// CHECK-12-NEXT: 0 | offset_to_top (0) +// CHECK-12-NEXT: 1 | Test5::C RTTI +// CHECK-12-NEXT: -- (Test5::A, 0) vtable address -- +// CHECK-12-NEXT: -- (Test5::B1, 0) vtable address -- +// CHECK-12-NEXT: -- (Test5::C, 0) vtable address -- +// CHECK-12-NEXT: 2 | void Test5::B1::f() +// CHECK-12-NEXT: 3 | void Test5::A::g() +// CHECK-12-NEXT: 4 | void Test5::C::h() +// CHECK-12-NEXT: 5 | offset_to_top (-16) +// CHECK-12-NEXT: 6 | Test5::C RTTI +// CHECK-12-NEXT: -- (Test5::A, 16) vtable address -- +// CHECK-12-NEXT: -- (Test5::B2, 16) vtable address -- +// CHECK-12-NEXT: 7 | void Test5::A::f() +// CHECK-12-NEXT: 8 | void Test5::B2::g() struct C : B1, B2 { virtual void h(); }; @@ -263,17 +305,17 @@ struct A2 { int a; }; -// CHECK: Vtable for 'Test6::C' (6 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test6::C RTTI -// CHECK-NEXT: -- (Test6::A1, 0) vtable address -- -// CHECK-NEXT: -- (Test6::C, 0) vtable address -- -// CHECK-NEXT: 2 | void Test6::C::f() -// CHECK-NEXT: 3 | offset_to_top (-16) -// CHECK-NEXT: 4 | Test6::C RTTI -// CHECK-NEXT: -- (Test6::A2, 16) vtable address -- -// CHECK-NEXT: 5 | void Test6::C::f() -// CHECK-NEXT: [this adjustment: -16 non-virtual] +// CHECK-13: Vtable for 'Test6::C' (6 entries). +// CHECK-13-NEXT: 0 | offset_to_top (0) +// CHECK-13-NEXT: 1 | Test6::C RTTI +// CHECK-13-NEXT: -- (Test6::A1, 0) vtable address -- +// CHECK-13-NEXT: -- (Test6::C, 0) vtable address -- +// CHECK-13-NEXT: 2 | void Test6::C::f() +// CHECK-13-NEXT: 3 | offset_to_top (-16) +// CHECK-13-NEXT: 4 | Test6::C RTTI +// CHECK-13-NEXT: -- (Test6::A2, 16) vtable address -- +// CHECK-13-NEXT: 5 | void Test6::C::f() +// CHECK-13-NEXT: [this adjustment: -16 non-virtual] struct C : A1, A2 { virtual void f(); }; @@ -296,25 +338,25 @@ struct B2 : A { }; struct C { virtual void c(); }; -// CHECK: Vtable for 'Test7::D' (10 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test7::D RTTI -// CHECK-NEXT: -- (Test7::C, 0) vtable address -- -// CHECK-NEXT: -- (Test7::D, 0) vtable address -- -// CHECK-NEXT: 2 | void Test7::C::c() -// CHECK-NEXT: 3 | void Test7::D::f() -// CHECK-NEXT: 4 | offset_to_top (-8) -// CHECK-NEXT: 5 | Test7::D RTTI -// CHECK-NEXT: -- (Test7::A, 8) vtable address -- -// CHECK-NEXT: -- (Test7::B1, 8) vtable address -- -// CHECK-NEXT: 6 | void Test7::D::f() -// CHECK-NEXT: [this adjustment: -8 non-virtual] -// CHECK-NEXT: 7 | offset_to_top (-24) -// CHECK-NEXT: 8 | Test7::D RTTI -// CHECK-NEXT: -- (Test7::A, 24) vtable address -- -// CHECK-NEXT: -- (Test7::B2, 24) vtable address -- -// CHECK-NEXT: 9 | void Test7::D::f() -// CHECK-NEXT: [this adjustment: -24 non-virtual] +// CHECK-14: Vtable for 'Test7::D' (10 entries). +// CHECK-14-NEXT: 0 | offset_to_top (0) +// CHECK-14-NEXT: 1 | Test7::D RTTI +// CHECK-14-NEXT: -- (Test7::C, 0) vtable address -- +// CHECK-14-NEXT: -- (Test7::D, 0) vtable address -- +// CHECK-14-NEXT: 2 | void Test7::C::c() +// CHECK-14-NEXT: 3 | void Test7::D::f() +// CHECK-14-NEXT: 4 | offset_to_top (-8) +// CHECK-14-NEXT: 5 | Test7::D RTTI +// CHECK-14-NEXT: -- (Test7::A, 8) vtable address -- +// CHECK-14-NEXT: -- (Test7::B1, 8) vtable address -- +// CHECK-14-NEXT: 6 | void Test7::D::f() +// CHECK-14-NEXT: [this adjustment: -8 non-virtual] +// CHECK-14-NEXT: 7 | offset_to_top (-24) +// CHECK-14-NEXT: 8 | Test7::D RTTI +// CHECK-14-NEXT: -- (Test7::A, 24) vtable address -- +// CHECK-14-NEXT: -- (Test7::B2, 24) vtable address -- +// CHECK-14-NEXT: 9 | void Test7::D::f() +// CHECK-14-NEXT: [this adjustment: -24 non-virtual] struct D : C, B1, B2 { virtual void f(); }; @@ -329,11 +371,11 @@ namespace Test8 { struct A { }; -// CHECK: Vtable for 'Test8::B' (3 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test8::B RTTI -// CHECK-NEXT: -- (Test8::B, 0) vtable address -- -// CHECK-NEXT: 2 | void Test8::B::f() +// CHECK-15: Vtable for 'Test8::B' (3 entries). +// CHECK-15-NEXT: 0 | offset_to_top (0) +// CHECK-15-NEXT: 1 | Test8::B RTTI +// CHECK-15-NEXT: -- (Test8::B, 0) vtable address -- +// CHECK-15-NEXT: 2 | void Test8::B::f() struct B : A { virtual void f(); }; @@ -348,13 +390,13 @@ namespace Test9 { struct A1 { int a1; }; struct A2 { int a2; }; -// CHECK: Vtable for 'Test9::B' (5 entries). -// CHECK-NEXT: 0 | vbase_offset (16) -// CHECK-NEXT: 1 | vbase_offset (12) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test9::B RTTI -// CHECK-NEXT: -- (Test9::B, 0) vtable address -- -// CHECK-NEXT: 4 | void Test9::B::f() +// CHECK-16: Vtable for 'Test9::B' (5 entries). +// CHECK-16-NEXT: 0 | vbase_offset (16) +// CHECK-16-NEXT: 1 | vbase_offset (12) +// CHECK-16-NEXT: 2 | offset_to_top (0) +// CHECK-16-NEXT: 3 | Test9::B RTTI +// CHECK-16-NEXT: -- (Test9::B, 0) vtable address -- +// CHECK-16-NEXT: 4 | void Test9::B::f() struct B : virtual A1, virtual A2 { int b; @@ -373,18 +415,18 @@ namespace Test10 { struct A1 { virtual void a1(); }; struct A2 { virtual void a2(); }; -// CHECK: Vtable for 'Test10::C' (7 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test10::C RTTI -// CHECK-NEXT: -- (Test10::A1, 0) vtable address -- -// CHECK-NEXT: -- (Test10::B, 0) vtable address -- -// CHECK-NEXT: -- (Test10::C, 0) vtable address -- -// CHECK-NEXT: 2 | void Test10::A1::a1() -// CHECK-NEXT: 3 | void Test10::C::f() -// CHECK-NEXT: 4 | offset_to_top (-8) -// CHECK-NEXT: 5 | Test10::C RTTI -// CHECK-NEXT: -- (Test10::A2, 8) vtable address -- -// CHECK-NEXT: 6 | void Test10::A2::a2() +// CHECK-17: Vtable for 'Test10::C' (7 entries). +// CHECK-17-NEXT: 0 | offset_to_top (0) +// CHECK-17-NEXT: 1 | Test10::C RTTI +// CHECK-17-NEXT: -- (Test10::A1, 0) vtable address -- +// CHECK-17-NEXT: -- (Test10::B, 0) vtable address -- +// CHECK-17-NEXT: -- (Test10::C, 0) vtable address -- +// CHECK-17-NEXT: 2 | void Test10::A1::a1() +// CHECK-17-NEXT: 3 | void Test10::C::f() +// CHECK-17-NEXT: 4 | offset_to_top (-8) +// CHECK-17-NEXT: 5 | Test10::C RTTI +// CHECK-17-NEXT: -- (Test10::A2, 8) vtable address -- +// CHECK-17-NEXT: 6 | void Test10::A2::a2() struct B : A1, A2 { int b; }; @@ -406,16 +448,16 @@ struct B : A1, virtual A2 { int b; }; -// CHECK: Vtable for 'Test11::C' (8 entries). -// CHECK-NEXT: 0 | vbase_offset (24) -// CHECK-NEXT: 1 | vbase_offset (8) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test11::C RTTI -// CHECK-NEXT: -- (Test11::C, 0) vtable address -- -// CHECK-NEXT: 4 | void Test11::C::f() -// CHECK-NEXT: 5 | vbase_offset (16) -// CHECK-NEXT: 6 | offset_to_top (-8) -// CHECK-NEXT: 7 | Test11::C RTTI +// CHECK-18: Vtable for 'Test11::C' (8 entries). +// CHECK-18-NEXT: 0 | vbase_offset (24) +// CHECK-18-NEXT: 1 | vbase_offset (8) +// CHECK-18-NEXT: 2 | offset_to_top (0) +// CHECK-18-NEXT: 3 | Test11::C RTTI +// CHECK-18-NEXT: -- (Test11::C, 0) vtable address -- +// CHECK-18-NEXT: 4 | void Test11::C::f() +// CHECK-18-NEXT: 5 | vbase_offset (16) +// CHECK-18-NEXT: 6 | offset_to_top (-8) +// CHECK-18-NEXT: 7 | Test11::C RTTI struct C : virtual B { virtual void f(); }; @@ -427,32 +469,32 @@ namespace Test12 { // Test that the right vcall offsets are generated in the right order. -// CHECK: Vtable for 'Test12::B' (19 entries). -// CHECK-NEXT: 0 | vbase_offset (8) -// CHECK-NEXT: 1 | offset_to_top (0) -// CHECK-NEXT: 2 | Test12::B RTTI -// CHECK-NEXT: -- (Test12::B, 0) vtable address -- -// CHECK-NEXT: 3 | void Test12::B::f() -// CHECK-NEXT: 4 | void Test12::B::a() -// CHECK-NEXT: 5 | vcall_offset (32) -// CHECK-NEXT: 6 | vcall_offset (16) -// CHECK-NEXT: 7 | vcall_offset (-8) -// CHECK-NEXT: 8 | vcall_offset (0) -// CHECK-NEXT: 9 | offset_to_top (-8) -// CHECK-NEXT: 10 | Test12::B RTTI -// CHECK-NEXT: -- (Test12::A, 8) vtable address -- -// CHECK-NEXT: -- (Test12::A1, 8) vtable address -- -// CHECK-NEXT: 11 | void Test12::A1::a1() -// CHECK-NEXT: 12 | void Test12::B::a() -// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] -// CHECK-NEXT: 13 | offset_to_top (-24) -// CHECK-NEXT: 14 | Test12::B RTTI -// CHECK-NEXT: -- (Test12::A2, 24) vtable address -- -// CHECK-NEXT: 15 | void Test12::A2::a2() -// CHECK-NEXT: 16 | offset_to_top (-40) -// CHECK-NEXT: 17 | Test12::B RTTI -// CHECK-NEXT: -- (Test12::A3, 40) vtable address -- -// CHECK-NEXT: 18 | void Test12::A3::a3() +// CHECK-19: Vtable for 'Test12::B' (19 entries). +// CHECK-19-NEXT: 0 | vbase_offset (8) +// CHECK-19-NEXT: 1 | offset_to_top (0) +// CHECK-19-NEXT: 2 | Test12::B RTTI +// CHECK-19-NEXT: -- (Test12::B, 0) vtable address -- +// CHECK-19-NEXT: 3 | void Test12::B::f() +// CHECK-19-NEXT: 4 | void Test12::B::a() +// CHECK-19-NEXT: 5 | vcall_offset (32) +// CHECK-19-NEXT: 6 | vcall_offset (16) +// CHECK-19-NEXT: 7 | vcall_offset (-8) +// CHECK-19-NEXT: 8 | vcall_offset (0) +// CHECK-19-NEXT: 9 | offset_to_top (-8) +// CHECK-19-NEXT: 10 | Test12::B RTTI +// CHECK-19-NEXT: -- (Test12::A, 8) vtable address -- +// CHECK-19-NEXT: -- (Test12::A1, 8) vtable address -- +// CHECK-19-NEXT: 11 | void Test12::A1::a1() +// CHECK-19-NEXT: 12 | void Test12::B::a() +// CHECK-19-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-19-NEXT: 13 | offset_to_top (-24) +// CHECK-19-NEXT: 14 | Test12::B RTTI +// CHECK-19-NEXT: -- (Test12::A2, 24) vtable address -- +// CHECK-19-NEXT: 15 | void Test12::A2::a2() +// CHECK-19-NEXT: 16 | offset_to_top (-40) +// CHECK-19-NEXT: 17 | Test12::B RTTI +// CHECK-19-NEXT: -- (Test12::A3, 40) vtable address -- +// CHECK-19-NEXT: 18 | void Test12::A3::a3() struct A1 { virtual void a1(); int a; @@ -493,16 +535,16 @@ struct B : virtual A { virtual void f(); }; -// CHECK: Vtable for 'Test13::C' (6 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vbase_offset (0) -// CHECK-NEXT: 2 | vcall_offset (0) -// CHECK-NEXT: 3 | offset_to_top (0) -// CHECK-NEXT: 4 | Test13::C RTTI -// CHECK-NEXT: -- (Test13::A, 0) vtable address -- -// CHECK-NEXT: -- (Test13::B, 0) vtable address -- -// CHECK-NEXT: -- (Test13::C, 0) vtable address -- -// CHECK-NEXT: 5 | void Test13::C::f() +// CHECK-20: Vtable for 'Test13::C' (6 entries). +// CHECK-20-NEXT: 0 | vbase_offset (0) +// CHECK-20-NEXT: 1 | vbase_offset (0) +// CHECK-20-NEXT: 2 | vcall_offset (0) +// CHECK-20-NEXT: 3 | offset_to_top (0) +// CHECK-20-NEXT: 4 | Test13::C RTTI +// CHECK-20-NEXT: -- (Test13::A, 0) vtable address -- +// CHECK-20-NEXT: -- (Test13::B, 0) vtable address -- +// CHECK-20-NEXT: -- (Test13::C, 0) vtable address -- +// CHECK-20-NEXT: 5 | void Test13::C::f() struct C : virtual B, virtual A { virtual void f(); }; @@ -522,16 +564,16 @@ struct B : A { }; struct C : virtual B { }; -// CHECK: Vtable for 'Test14::D' (5 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vcall_offset (0) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test14::D RTTI -// CHECK-NEXT: -- (Test14::A, 0) vtable address -- -// CHECK-NEXT: -- (Test14::B, 0) vtable address -- -// CHECK-NEXT: -- (Test14::C, 0) vtable address -- -// CHECK-NEXT: -- (Test14::D, 0) vtable address -- -// CHECK-NEXT: 4 | void Test14::D::f() +// CHECK-21: Vtable for 'Test14::D' (5 entries). +// CHECK-21-NEXT: 0 | vbase_offset (0) +// CHECK-21-NEXT: 1 | vcall_offset (0) +// CHECK-21-NEXT: 2 | offset_to_top (0) +// CHECK-21-NEXT: 3 | Test14::D RTTI +// CHECK-21-NEXT: -- (Test14::A, 0) vtable address -- +// CHECK-21-NEXT: -- (Test14::B, 0) vtable address -- +// CHECK-21-NEXT: -- (Test14::C, 0) vtable address -- +// CHECK-21-NEXT: -- (Test14::D, 0) vtable address -- +// CHECK-21-NEXT: 4 | void Test14::D::f() struct D : C, virtual B { virtual void f(); }; @@ -547,22 +589,22 @@ struct B { virtual void b(); }; struct C : virtual B { }; -// CHECK: Vtable for 'Test15::D' (11 entries). -// CHECK-NEXT: 0 | vbase_offset (8) -// CHECK-NEXT: 1 | vbase_offset (8) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test15::D RTTI -// CHECK-NEXT: -- (Test15::A, 0) vtable address -- -// CHECK-NEXT: -- (Test15::D, 0) vtable address -- -// CHECK-NEXT: 4 | void Test15::A::a() -// CHECK-NEXT: 5 | void Test15::D::f() -// CHECK-NEXT: 6 | vbase_offset (0) -// CHECK-NEXT: 7 | vcall_offset (0) -// CHECK-NEXT: 8 | offset_to_top (-8) -// CHECK-NEXT: 9 | Test15::D RTTI -// CHECK-NEXT: -- (Test15::B, 8) vtable address -- -// CHECK-NEXT: -- (Test15::C, 8) vtable address -- -// CHECK-NEXT: 10 | void Test15::B::b() +// CHECK-22: Vtable for 'Test15::D' (11 entries). +// CHECK-22-NEXT: 0 | vbase_offset (8) +// CHECK-22-NEXT: 1 | vbase_offset (8) +// CHECK-22-NEXT: 2 | offset_to_top (0) +// CHECK-22-NEXT: 3 | Test15::D RTTI +// CHECK-22-NEXT: -- (Test15::A, 0) vtable address -- +// CHECK-22-NEXT: -- (Test15::D, 0) vtable address -- +// CHECK-22-NEXT: 4 | void Test15::A::a() +// CHECK-22-NEXT: 5 | void Test15::D::f() +// CHECK-22-NEXT: 6 | vbase_offset (0) +// CHECK-22-NEXT: 7 | vcall_offset (0) +// CHECK-22-NEXT: 8 | offset_to_top (-8) +// CHECK-22-NEXT: 9 | Test15::D RTTI +// CHECK-22-NEXT: -- (Test15::B, 8) vtable address -- +// CHECK-22-NEXT: -- (Test15::C, 8) vtable address -- +// CHECK-22-NEXT: 10 | void Test15::B::b() struct D : A, virtual B, virtual C { virtual void f(); }; @@ -579,30 +621,30 @@ struct B { virtual ~B(); }; struct C : A, B { virtual ~C(); }; -// CHECK: Vtable for 'Test16::D' (15 entries). -// CHECK-NEXT: 0 | vbase_offset (8) -// CHECK-NEXT: 1 | offset_to_top (0) -// CHECK-NEXT: 2 | Test16::D RTTI -// CHECK-NEXT: -- (Test16::D, 0) vtable address -- -// CHECK-NEXT: 3 | void Test16::D::f() -// CHECK-NEXT: 4 | Test16::D::~D() [complete] -// CHECK-NEXT: 5 | Test16::D::~D() [deleting] -// CHECK-NEXT: 6 | vcall_offset (-8) -// CHECK-NEXT: 7 | offset_to_top (-8) -// CHECK-NEXT: 8 | Test16::D RTTI -// CHECK-NEXT: -- (Test16::A, 8) vtable address -- -// CHECK-NEXT: -- (Test16::C, 8) vtable address -- -// CHECK-NEXT: 9 | Test16::D::~D() [complete] -// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] -// CHECK-NEXT: 10 | Test16::D::~D() [deleting] -// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] -// CHECK-NEXT: 11 | offset_to_top (-16) -// CHECK-NEXT: 12 | Test16::D RTTI -// CHECK-NEXT: -- (Test16::B, 16) vtable address -- -// CHECK-NEXT: 13 | Test16::D::~D() [complete] -// CHECK-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] -// CHECK-NEXT: 14 | Test16::D::~D() [deleting] -// CHECK-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] +// CHECK-23: Vtable for 'Test16::D' (15 entries). +// CHECK-23-NEXT: 0 | vbase_offset (8) +// CHECK-23-NEXT: 1 | offset_to_top (0) +// CHECK-23-NEXT: 2 | Test16::D RTTI +// CHECK-23-NEXT: -- (Test16::D, 0) vtable address -- +// CHECK-23-NEXT: 3 | void Test16::D::f() +// CHECK-23-NEXT: 4 | Test16::D::~D() [complete] +// CHECK-23-NEXT: 5 | Test16::D::~D() [deleting] +// CHECK-23-NEXT: 6 | vcall_offset (-8) +// CHECK-23-NEXT: 7 | offset_to_top (-8) +// CHECK-23-NEXT: 8 | Test16::D RTTI +// CHECK-23-NEXT: -- (Test16::A, 8) vtable address -- +// CHECK-23-NEXT: -- (Test16::C, 8) vtable address -- +// CHECK-23-NEXT: 9 | Test16::D::~D() [complete] +// CHECK-23-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-23-NEXT: 10 | Test16::D::~D() [deleting] +// CHECK-23-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-23-NEXT: 11 | offset_to_top (-16) +// CHECK-23-NEXT: 12 | Test16::D RTTI +// CHECK-23-NEXT: -- (Test16::B, 16) vtable address -- +// CHECK-23-NEXT: 13 | Test16::D::~D() [complete] +// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] +// CHECK-23-NEXT: 14 | Test16::D::~D() [deleting] +// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] struct D : virtual C { virtual void f(); }; @@ -618,26 +660,26 @@ struct B : virtual A { virtual void f(); }; struct C : virtual A { virtual void f(); }; struct D : virtual B, virtual C { virtual void f(); }; -// CHECK: Vtable for 'Test17::E' (13 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vbase_offset (8) -// CHECK-NEXT: 2 | vbase_offset (0) -// CHECK-NEXT: 3 | vbase_offset (0) -// CHECK-NEXT: 4 | vcall_offset (0) -// CHECK-NEXT: 5 | offset_to_top (0) -// CHECK-NEXT: 6 | Test17::E RTTI -// CHECK-NEXT: -- (Test17::A, 0) vtable address -- -// CHECK-NEXT: -- (Test17::B, 0) vtable address -- -// CHECK-NEXT: -- (Test17::D, 0) vtable address -- -// CHECK-NEXT: -- (Test17::E, 0) vtable address -- -// CHECK-NEXT: 7 | void Test17::E::f() -// CHECK-NEXT: 8 | vbase_offset (-8) -// CHECK-NEXT: 9 | vcall_offset (-8) -// CHECK-NEXT: 10 | offset_to_top (-8) -// CHECK-NEXT: 11 | Test17::E RTTI -// CHECK-NEXT: -- (Test17::C, 8) vtable address -- -// CHECK-NEXT: 12 | void Test17::E::f() -// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-24: Vtable for 'Test17::E' (13 entries). +// CHECK-24-NEXT: 0 | vbase_offset (0) +// CHECK-24-NEXT: 1 | vbase_offset (8) +// CHECK-24-NEXT: 2 | vbase_offset (0) +// CHECK-24-NEXT: 3 | vbase_offset (0) +// CHECK-24-NEXT: 4 | vcall_offset (0) +// CHECK-24-NEXT: 5 | offset_to_top (0) +// CHECK-24-NEXT: 6 | Test17::E RTTI +// CHECK-24-NEXT: -- (Test17::A, 0) vtable address -- +// CHECK-24-NEXT: -- (Test17::B, 0) vtable address -- +// CHECK-24-NEXT: -- (Test17::D, 0) vtable address -- +// CHECK-24-NEXT: -- (Test17::E, 0) vtable address -- +// CHECK-24-NEXT: 7 | void Test17::E::f() +// CHECK-24-NEXT: 8 | vbase_offset (-8) +// CHECK-24-NEXT: 9 | vcall_offset (-8) +// CHECK-24-NEXT: 10 | offset_to_top (-8) +// CHECK-24-NEXT: 11 | Test17::E RTTI +// CHECK-24-NEXT: -- (Test17::C, 8) vtable address -- +// CHECK-24-NEXT: 12 | void Test17::E::f() +// CHECK-24-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] class E : virtual D { virtual void f(); }; @@ -662,97 +704,97 @@ struct C : A, B { virtual void g(); }; -// CHECK: Vtable for 'Test18::D' (24 entries). -// CHECK-NEXT: 0 | vbase_offset (8) -// CHECK-NEXT: 1 | vbase_offset (0) -// CHECK-NEXT: 2 | vbase_offset (0) -// CHECK-NEXT: 3 | vcall_offset (8) -// CHECK-NEXT: 4 | vcall_offset (0) -// CHECK-NEXT: 5 | offset_to_top (0) -// CHECK-NEXT: 6 | Test18::D RTTI -// CHECK-NEXT: -- (Test18::A, 0) vtable address -- -// CHECK-NEXT: -- (Test18::B, 0) vtable address -- -// CHECK-NEXT: -- (Test18::D, 0) vtable address -- -// CHECK-NEXT: 7 | void Test18::D::f() -// CHECK-NEXT: 8 | void Test18::C::g() -// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] -// CHECK-NEXT: 9 | void Test18::D::h() -// CHECK-NEXT: 10 | vcall_offset (0) -// CHECK-NEXT: 11 | vcall_offset (-8) -// CHECK-NEXT: 12 | vbase_offset (-8) -// CHECK-NEXT: 13 | offset_to_top (-8) -// CHECK-NEXT: 14 | Test18::D RTTI -// CHECK-NEXT: -- (Test18::A, 8) vtable address -- -// CHECK-NEXT: -- (Test18::C, 8) vtable address -- -// CHECK-NEXT: 15 | void Test18::D::f() -// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] -// CHECK-NEXT: 16 | void Test18::C::g() -// CHECK-NEXT: 17 | vbase_offset (-16) -// CHECK-NEXT: 18 | vcall_offset (-8) -// CHECK-NEXT: 19 | vcall_offset (-16) -// CHECK-NEXT: 20 | offset_to_top (-16) -// CHECK-NEXT: 21 | Test18::D RTTI -// CHECK-NEXT: -- (Test18::B, 16) vtable address -- -// 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::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::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() +// CHECK-25: Vtable for 'Test18::D' (24 entries). +// CHECK-25-NEXT: 0 | vbase_offset (8) +// CHECK-25-NEXT: 1 | vbase_offset (0) +// CHECK-25-NEXT: 2 | vbase_offset (0) +// CHECK-25-NEXT: 3 | vcall_offset (8) +// CHECK-25-NEXT: 4 | vcall_offset (0) +// CHECK-25-NEXT: 5 | offset_to_top (0) +// CHECK-25-NEXT: 6 | Test18::D RTTI +// CHECK-25-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-25-NEXT: -- (Test18::B, 0) vtable address -- +// CHECK-25-NEXT: -- (Test18::D, 0) vtable address -- +// CHECK-25-NEXT: 7 | void Test18::D::f() +// CHECK-25-NEXT: 8 | void Test18::C::g() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-25-NEXT: 9 | void Test18::D::h() +// CHECK-25-NEXT: 10 | vcall_offset (0) +// CHECK-25-NEXT: 11 | vcall_offset (-8) +// CHECK-25-NEXT: 12 | vbase_offset (-8) +// CHECK-25-NEXT: 13 | offset_to_top (-8) +// CHECK-25-NEXT: 14 | Test18::D RTTI +// CHECK-25-NEXT: -- (Test18::A, 8) vtable address -- +// CHECK-25-NEXT: -- (Test18::C, 8) vtable address -- +// CHECK-25-NEXT: 15 | void Test18::D::f() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-25-NEXT: 16 | void Test18::C::g() +// CHECK-25-NEXT: 17 | vbase_offset (-16) +// CHECK-25-NEXT: 18 | vcall_offset (-8) +// CHECK-25-NEXT: 19 | vcall_offset (-16) +// CHECK-25-NEXT: 20 | offset_to_top (-16) +// CHECK-25-NEXT: 21 | Test18::D RTTI +// CHECK-25-NEXT: -- (Test18::B, 16) vtable address -- +// CHECK-25-NEXT: 22 | void Test18::D::f() +// CHECK-25-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset] +// CHECK-25-NEXT: 23 | [unused] void Test18::C::g() + +// CHECK-25: Construction vtable for ('Test18::B', 0) in 'Test18::D' (7 entries). +// CHECK-25-NEXT: 0 | vbase_offset (0) +// CHECK-25-NEXT: 1 | vcall_offset (0) +// CHECK-25-NEXT: 2 | vcall_offset (0) +// CHECK-25-NEXT: 3 | offset_to_top (0) +// CHECK-25-NEXT: 4 | Test18::B RTTI +// CHECK-25-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-25-NEXT: -- (Test18::B, 0) vtable address -- +// CHECK-25-NEXT: 5 | void Test18::B::f() +// CHECK-25-NEXT: 6 | void Test18::A::g() + +// CHECK-25: Construction vtable for ('Test18::C', 8) in 'Test18::D' (20 entries). +// CHECK-25-NEXT: 0 | vcall_offset (0) +// CHECK-25-NEXT: 1 | vcall_offset (0) +// CHECK-25-NEXT: 2 | vbase_offset (-8) +// CHECK-25-NEXT: 3 | offset_to_top (0) +// CHECK-25-NEXT: 4 | Test18::C RTTI +// CHECK-25-NEXT: -- (Test18::A, 8) vtable address -- +// CHECK-25-NEXT: -- (Test18::C, 8) vtable address -- +// CHECK-25-NEXT: 5 | void Test18::A::f() +// CHECK-25-NEXT: 6 | void Test18::C::g() +// CHECK-25-NEXT: 7 | vbase_offset (-16) +// CHECK-25-NEXT: 8 | vcall_offset (-8) +// CHECK-25-NEXT: 9 | vcall_offset (0) +// CHECK-25-NEXT: 10 | offset_to_top (-8) +// CHECK-25-NEXT: 11 | Test18::C RTTI +// CHECK-25-NEXT: -- (Test18::B, 16) vtable address -- +// CHECK-25-NEXT: 12 | void Test18::B::f() +// CHECK-25-NEXT: 13 | [unused] void Test18::C::g() +// CHECK-25-NEXT: 14 | vcall_offset (8) +// CHECK-25-NEXT: 15 | vcall_offset (16) +// CHECK-25-NEXT: 16 | offset_to_top (8) +// CHECK-25-NEXT: 17 | Test18::C RTTI +// CHECK-25-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-25-NEXT: 18 | void Test18::B::f() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-25-NEXT: 19 | void Test18::C::g() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] + +// CHECK-25: Construction vtable for ('Test18::B', 16) in 'Test18::D' (13 entries). +// CHECK-25-NEXT: 0 | vbase_offset (-16) +// CHECK-25-NEXT: 1 | vcall_offset (-16) +// CHECK-25-NEXT: 2 | vcall_offset (0) +// CHECK-25-NEXT: 3 | offset_to_top (0) +// CHECK-25-NEXT: 4 | Test18::B RTTI +// CHECK-25-NEXT: -- (Test18::B, 16) vtable address -- +// CHECK-25-NEXT: 5 | void Test18::B::f() +// CHECK-25-NEXT: 6 | [unused] void Test18::A::g() +// CHECK-25-NEXT: 7 | vcall_offset (0) +// CHECK-25-NEXT: 8 | vcall_offset (16) +// CHECK-25-NEXT: 9 | offset_to_top (16) +// CHECK-25-NEXT: 10 | Test18::B RTTI +// CHECK-25-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-25-NEXT: 11 | void Test18::B::f() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-25-NEXT: 12 | void Test18::A::g() struct D : virtual B, virtual C, virtual A { virtual void f(); @@ -782,27 +824,27 @@ struct C { virtual void c(); }; -// CHECK: Vtable for 'Test19::D' (13 entries). -// CHECK-NEXT: 0 | vbase_offset (24) -// CHECK-NEXT: 1 | offset_to_top (0) -// CHECK-NEXT: 2 | Test19::D RTTI -// CHECK-NEXT: -- (Test19::C, 0) vtable address -- -// CHECK-NEXT: -- (Test19::D, 0) vtable address -- -// CHECK-NEXT: 3 | void Test19::C::c() -// CHECK-NEXT: 4 | void Test19::D::f() -// CHECK-NEXT: 5 | offset_to_top (-8) -// CHECK-NEXT: 6 | Test19::D RTTI -// CHECK-NEXT: -- (Test19::A, 8) vtable address -- -// CHECK-NEXT: -- (Test19::B, 8) vtable address -- -// CHECK-NEXT: 7 | void Test19::D::f() -// CHECK-NEXT: [this adjustment: -8 non-virtual] -// CHECK-NEXT: 8 | void Test19::B::g() -// CHECK-NEXT: 9 | vcall_offset (-24) -// CHECK-NEXT: 10 | offset_to_top (-24) -// CHECK-NEXT: 11 | Test19::D RTTI -// CHECK-NEXT: -- (Test19::A, 24) vtable address -- -// CHECK-NEXT: 12 | void Test19::D::f() -// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-26: Vtable for 'Test19::D' (13 entries). +// CHECK-26-NEXT: 0 | vbase_offset (24) +// CHECK-26-NEXT: 1 | offset_to_top (0) +// CHECK-26-NEXT: 2 | Test19::D RTTI +// CHECK-26-NEXT: -- (Test19::C, 0) vtable address -- +// CHECK-26-NEXT: -- (Test19::D, 0) vtable address -- +// CHECK-26-NEXT: 3 | void Test19::C::c() +// CHECK-26-NEXT: 4 | void Test19::D::f() +// CHECK-26-NEXT: 5 | offset_to_top (-8) +// CHECK-26-NEXT: 6 | Test19::D RTTI +// CHECK-26-NEXT: -- (Test19::A, 8) vtable address -- +// CHECK-26-NEXT: -- (Test19::B, 8) vtable address -- +// CHECK-26-NEXT: 7 | void Test19::D::f() +// CHECK-26-NEXT: [this adjustment: -8 non-virtual] +// CHECK-26-NEXT: 8 | void Test19::B::g() +// CHECK-26-NEXT: 9 | vcall_offset (-24) +// CHECK-26-NEXT: 10 | offset_to_top (-24) +// CHECK-26-NEXT: 11 | Test19::D RTTI +// CHECK-26-NEXT: -- (Test19::A, 24) vtable address -- +// CHECK-26-NEXT: 12 | void Test19::D::f() +// CHECK-26-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] struct D : C, B, virtual A { virtual void f(); }; @@ -821,20 +863,20 @@ struct A { struct B : A { }; -// CHECK: Vtable for 'Test20::C' (9 entries). -// CHECK-NEXT: 0 | offset_to_top (0) -// CHECK-NEXT: 1 | Test20::C RTTI -// CHECK-NEXT: -- (Test20::A, 0) vtable address -- -// CHECK-NEXT: -- (Test20::C, 0) vtable address -- -// CHECK-NEXT: 2 | void Test20::C::f() [pure] -// CHECK-NEXT: 3 | void Test20::A::g() -// CHECK-NEXT: 4 | void Test20::C::h() -// CHECK-NEXT: 5 | offset_to_top (-8) -// CHECK-NEXT: 6 | Test20::C RTTI -// CHECK-NEXT: -- (Test20::A, 8) vtable address -- -// CHECK-NEXT: -- (Test20::B, 8) vtable address -- -// CHECK-NEXT: 7 | void Test20::C::f() [pure] -// CHECK-NEXT: 8 | void Test20::A::g() +// CHECK-27: Vtable for 'Test20::C' (9 entries). +// CHECK-27-NEXT: 0 | offset_to_top (0) +// CHECK-27-NEXT: 1 | Test20::C RTTI +// CHECK-27-NEXT: -- (Test20::A, 0) vtable address -- +// CHECK-27-NEXT: -- (Test20::C, 0) vtable address -- +// CHECK-27-NEXT: 2 | void Test20::C::f() [pure] +// CHECK-27-NEXT: 3 | void Test20::A::g() +// CHECK-27-NEXT: 4 | void Test20::C::h() +// CHECK-27-NEXT: 5 | offset_to_top (-8) +// CHECK-27-NEXT: 6 | Test20::C RTTI +// CHECK-27-NEXT: -- (Test20::A, 8) vtable address -- +// CHECK-27-NEXT: -- (Test20::B, 8) vtable address -- +// CHECK-27-NEXT: 7 | void Test20::C::f() [pure] +// CHECK-27-NEXT: 8 | void Test20::A::g() struct C : A, B { virtual void f() = 0; virtual void h(); @@ -856,36 +898,36 @@ class D : virtual C { }; class E : virtual C { }; -// CHECK: Vtable for 'Test21::F' (16 entries). -// CHECK-NEXT: 0 | vbase_offset (8) -// CHECK-NEXT: 1 | vbase_offset (0) -// CHECK-NEXT: 2 | vbase_offset (0) -// CHECK-NEXT: 3 | vbase_offset (0) -// CHECK-NEXT: 4 | vbase_offset (0) -// CHECK-NEXT: 5 | vcall_offset (0) -// CHECK-NEXT: 6 | offset_to_top (0) -// CHECK-NEXT: 7 | Test21::F RTTI -// CHECK-NEXT: -- (Test21::A, 0) vtable address -- -// CHECK-NEXT: -- (Test21::B, 0) vtable address -- -// CHECK-NEXT: -- (Test21::C, 0) vtable address -- -// CHECK-NEXT: -- (Test21::D, 0) vtable address -- -// CHECK-NEXT: -- (Test21::F, 0) vtable address -- -// CHECK-NEXT: 8 | void Test21::F::f() -// CHECK-NEXT: 9 | vbase_offset (-8) -// CHECK-NEXT: 10 | vbase_offset (-8) -// CHECK-NEXT: 11 | vbase_offset (-8) -// CHECK-NEXT: 12 | vcall_offset (-8) -// CHECK-NEXT: 13 | offset_to_top (-8) -// CHECK-NEXT: 14 | Test21::F RTTI -// CHECK-NEXT: -- (Test21::E, 8) vtable address -- -// CHECK-NEXT: 15 | [unused] void Test21::F::f() +// CHECK-28: Vtable for 'Test21::F' (16 entries). +// CHECK-28-NEXT: 0 | vbase_offset (8) +// CHECK-28-NEXT: 1 | vbase_offset (0) +// CHECK-28-NEXT: 2 | vbase_offset (0) +// CHECK-28-NEXT: 3 | vbase_offset (0) +// CHECK-28-NEXT: 4 | vbase_offset (0) +// CHECK-28-NEXT: 5 | vcall_offset (0) +// CHECK-28-NEXT: 6 | offset_to_top (0) +// CHECK-28-NEXT: 7 | Test21::F RTTI +// CHECK-28-NEXT: -- (Test21::A, 0) vtable address -- +// CHECK-28-NEXT: -- (Test21::B, 0) vtable address -- +// CHECK-28-NEXT: -- (Test21::C, 0) vtable address -- +// CHECK-28-NEXT: -- (Test21::D, 0) vtable address -- +// CHECK-28-NEXT: -- (Test21::F, 0) vtable address -- +// CHECK-28-NEXT: 8 | void Test21::F::f() +// CHECK-28-NEXT: 9 | vbase_offset (-8) +// CHECK-28-NEXT: 10 | vbase_offset (-8) +// CHECK-28-NEXT: 11 | vbase_offset (-8) +// CHECK-28-NEXT: 12 | vcall_offset (-8) +// CHECK-28-NEXT: 13 | offset_to_top (-8) +// CHECK-28-NEXT: 14 | Test21::F RTTI +// CHECK-28-NEXT: -- (Test21::E, 8) vtable address -- +// CHECK-28-NEXT: 15 | [unused] void Test21::F::f() // -// CHECK: Virtual base offset offsets for 'Test21::F' (5 entries). -// CHECK-NEXT: Test21::A | -32 -// CHECK-NEXT: Test21::B | -40 -// CHECK-NEXT: Test21::C | -48 -// CHECK-NEXT: Test21::D | -56 -// CHECK-NEXT: Test21::E | -64 +// CHECK-28: Virtual base offset offsets for 'Test21::F' (5 entries). +// CHECK-28-NEXT: Test21::A | -32 +// CHECK-28-NEXT: Test21::B | -40 +// CHECK-28-NEXT: Test21::C | -48 +// CHECK-28-NEXT: Test21::D | -56 +// CHECK-28-NEXT: Test21::E | -64 class F : virtual D, virtual E { virtual void f(); }; @@ -904,22 +946,22 @@ struct V2 : virtual V1 { int v2; }; -// CHECK: Vtable for 'Test22::C' (8 entries). -// CHECK-NEXT: 0 | vbase_offset (16) -// CHECK-NEXT: 1 | vbase_offset (12) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test22::C RTTI -// CHECK-NEXT: -- (Test22::C, 0) vtable address -- -// CHECK-NEXT: 4 | void Test22::C::f() -// CHECK-NEXT: 5 | vbase_offset (-4) -// CHECK-NEXT: 6 | offset_to_top (-16) -// CHECK-NEXT: 7 | Test22::C RTTI -// CHECK-NEXT: -- (Test22::V2, 16) vtable address -- +// CHECK-29: Vtable for 'Test22::C' (8 entries). +// CHECK-29-NEXT: 0 | vbase_offset (16) +// CHECK-29-NEXT: 1 | vbase_offset (12) +// CHECK-29-NEXT: 2 | offset_to_top (0) +// CHECK-29-NEXT: 3 | Test22::C RTTI +// CHECK-29-NEXT: -- (Test22::C, 0) vtable address -- +// CHECK-29-NEXT: 4 | void Test22::C::f() +// CHECK-29-NEXT: 5 | vbase_offset (-4) +// CHECK-29-NEXT: 6 | offset_to_top (-16) +// CHECK-29-NEXT: 7 | Test22::C RTTI +// CHECK-29-NEXT: -- (Test22::V2, 16) vtable address -- -// CHECK: Construction vtable for ('Test22::V2', 16) in 'Test22::C' (3 entries). -// CHECK-NEXT: 0 | vbase_offset (-4) -// CHECK-NEXT: 1 | offset_to_top (0) -// CHECK-NEXT: 2 | Test22::V2 RTTI +// CHECK-29: Construction vtable for ('Test22::V2', 16) in 'Test22::C' (3 entries). +// CHECK-29-NEXT: 0 | vbase_offset (-4) +// CHECK-29-NEXT: 1 | offset_to_top (0) +// CHECK-29-NEXT: 2 | Test22::V2 RTTI struct C : virtual V1, virtual V2 { int c; @@ -943,34 +985,34 @@ struct C : A, virtual B { int c; }; -// CHECK: Vtable for 'Test23::D' (7 entries). -// CHECK-NEXT: 0 | vbase_offset (20) -// CHECK-NEXT: 1 | vbase_offset (24) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test23::D RTTI -// CHECK-NEXT: -- (Test23::C, 0) vtable address -- -// CHECK-NEXT: -- (Test23::D, 0) vtable address -- -// CHECK-NEXT: 4 | vbase_offset (-4) -// CHECK-NEXT: 5 | offset_to_top (-24) -// CHECK-NEXT: 6 | Test23::D RTTI -// CHECK-NEXT: -- (Test23::B, 24) vtable address -- - -// CHECK: Construction vtable for ('Test23::C', 0) in 'Test23::D' (7 entries). -// CHECK-NEXT: 0 | vbase_offset (20) -// CHECK-NEXT: 1 | vbase_offset (24) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test23::C RTTI -// CHECK-NEXT: -- (Test23::C, 0) vtable address -- -// CHECK-NEXT: 4 | vbase_offset (-4) -// CHECK-NEXT: 5 | offset_to_top (-24) -// CHECK-NEXT: 6 | Test23::C RTTI -// CHECK-NEXT: -- (Test23::B, 24) vtable address -- - -// CHECK: Construction vtable for ('Test23::B', 24) in 'Test23::D' (3 entries). -// CHECK-NEXT: 0 | vbase_offset (-4) -// CHECK-NEXT: 1 | offset_to_top (0) -// CHECK-NEXT: 2 | Test23::B RTTI -// CHECK-NEXT: -- (Test23::B, 24) vtable address -- +// CHECK-30: Vtable for 'Test23::D' (7 entries). +// CHECK-30-NEXT: 0 | vbase_offset (20) +// CHECK-30-NEXT: 1 | vbase_offset (24) +// CHECK-30-NEXT: 2 | offset_to_top (0) +// CHECK-30-NEXT: 3 | Test23::D RTTI +// CHECK-30-NEXT: -- (Test23::C, 0) vtable address -- +// CHECK-30-NEXT: -- (Test23::D, 0) vtable address -- +// CHECK-30-NEXT: 4 | vbase_offset (-4) +// CHECK-30-NEXT: 5 | offset_to_top (-24) +// CHECK-30-NEXT: 6 | Test23::D RTTI +// CHECK-30-NEXT: -- (Test23::B, 24) vtable address -- + +// CHECK-30: Construction vtable for ('Test23::C', 0) in 'Test23::D' (7 entries). +// CHECK-30-NEXT: 0 | vbase_offset (20) +// CHECK-30-NEXT: 1 | vbase_offset (24) +// CHECK-30-NEXT: 2 | offset_to_top (0) +// CHECK-30-NEXT: 3 | Test23::C RTTI +// CHECK-30-NEXT: -- (Test23::C, 0) vtable address -- +// CHECK-30-NEXT: 4 | vbase_offset (-4) +// CHECK-30-NEXT: 5 | offset_to_top (-24) +// CHECK-30-NEXT: 6 | Test23::C RTTI +// CHECK-30-NEXT: -- (Test23::B, 24) vtable address -- + +// CHECK-30: Construction vtable for ('Test23::B', 24) in 'Test23::D' (3 entries). +// CHECK-30-NEXT: 0 | vbase_offset (-4) +// CHECK-30-NEXT: 1 | offset_to_top (0) +// CHECK-30-NEXT: 2 | Test23::B RTTI +// CHECK-30-NEXT: -- (Test23::B, 24) vtable address -- struct D : virtual A, virtual B, C { int d; @@ -978,7 +1020,7 @@ struct D : virtual A, virtual B, C { void f(); }; void D::f() { } - + D d; } namespace Test24 { @@ -992,43 +1034,43 @@ struct A { struct B : virtual A { }; struct C : virtual A { }; -// CHECK: Vtable for 'Test24::D' (10 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vcall_offset (0) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test24::D RTTI -// CHECK-NEXT: -- (Test24::A, 0) vtable address -- -// CHECK-NEXT: -- (Test24::B, 0) vtable address -- -// CHECK-NEXT: -- (Test24::D, 0) vtable address -- -// CHECK-NEXT: 4 | void Test24::D::f() -// CHECK-NEXT: 5 | vbase_offset (-8) -// CHECK-NEXT: 6 | vcall_offset (-8) -// CHECK-NEXT: 7 | offset_to_top (-8) -// CHECK-NEXT: 8 | Test24::D RTTI -// CHECK-NEXT: -- (Test24::C, 8) vtable address -- -// CHECK-NEXT: 9 | [unused] void Test24::D::f() - -// CHECK: Construction vtable for ('Test24::B', 0) in 'Test24::D' (5 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vcall_offset (0) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test24::B RTTI -// CHECK-NEXT: -- (Test24::A, 0) vtable address -- -// CHECK-NEXT: -- (Test24::B, 0) vtable address -- -// CHECK-NEXT: 4 | void Test24::A::f() - -// CHECK: Construction vtable for ('Test24::C', 8) in 'Test24::D' (9 entries). -// CHECK-NEXT: 0 | vbase_offset (-8) -// CHECK-NEXT: 1 | vcall_offset (-8) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test24::C RTTI -// CHECK-NEXT: -- (Test24::C, 8) vtable address -- -// CHECK-NEXT: 4 | [unused] void Test24::A::f() -// CHECK-NEXT: 5 | vcall_offset (0) -// CHECK-NEXT: 6 | offset_to_top (8) -// CHECK-NEXT: 7 | Test24::C RTTI -// CHECK-NEXT: -- (Test24::A, 0) vtable address -- -// CHECK-NEXT: 8 | void Test24::A::f() +// CHECK-31: Vtable for 'Test24::D' (10 entries). +// CHECK-31-NEXT: 0 | vbase_offset (0) +// CHECK-31-NEXT: 1 | vcall_offset (0) +// CHECK-31-NEXT: 2 | offset_to_top (0) +// CHECK-31-NEXT: 3 | Test24::D RTTI +// CHECK-31-NEXT: -- (Test24::A, 0) vtable address -- +// CHECK-31-NEXT: -- (Test24::B, 0) vtable address -- +// CHECK-31-NEXT: -- (Test24::D, 0) vtable address -- +// CHECK-31-NEXT: 4 | void Test24::D::f() +// CHECK-31-NEXT: 5 | vbase_offset (-8) +// CHECK-31-NEXT: 6 | vcall_offset (-8) +// CHECK-31-NEXT: 7 | offset_to_top (-8) +// CHECK-31-NEXT: 8 | Test24::D RTTI +// CHECK-31-NEXT: -- (Test24::C, 8) vtable address -- +// CHECK-31-NEXT: 9 | [unused] void Test24::D::f() + +// CHECK-31: Construction vtable for ('Test24::B', 0) in 'Test24::D' (5 entries). +// CHECK-31-NEXT: 0 | vbase_offset (0) +// CHECK-31-NEXT: 1 | vcall_offset (0) +// CHECK-31-NEXT: 2 | offset_to_top (0) +// CHECK-31-NEXT: 3 | Test24::B RTTI +// CHECK-31-NEXT: -- (Test24::A, 0) vtable address -- +// CHECK-31-NEXT: -- (Test24::B, 0) vtable address -- +// CHECK-31-NEXT: 4 | void Test24::A::f() + +// CHECK-31: Construction vtable for ('Test24::C', 8) in 'Test24::D' (9 entries). +// CHECK-31-NEXT: 0 | vbase_offset (-8) +// CHECK-31-NEXT: 1 | vcall_offset (-8) +// CHECK-31-NEXT: 2 | offset_to_top (0) +// CHECK-31-NEXT: 3 | Test24::C RTTI +// CHECK-31-NEXT: -- (Test24::C, 8) vtable address -- +// CHECK-31-NEXT: 4 | [unused] void Test24::A::f() +// CHECK-31-NEXT: 5 | vcall_offset (0) +// CHECK-31-NEXT: 6 | offset_to_top (8) +// CHECK-31-NEXT: 7 | Test24::C RTTI +// CHECK-31-NEXT: -- (Test24::A, 0) vtable address -- +// CHECK-31-NEXT: 8 | void Test24::A::f() struct D : B, C { virtual void f(); }; @@ -1047,44 +1089,44 @@ struct V { struct A : virtual V { }; struct B : virtual V { }; -// CHECK: Vtable for 'Test25::C' (11 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vcall_offset (0) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test25::C RTTI -// CHECK-NEXT: -- (Test25::A, 0) vtable address -- -// CHECK-NEXT: -- (Test25::C, 0) vtable address -- -// CHECK-NEXT: -- (Test25::V, 0) vtable address -- -// CHECK-NEXT: 4 | void Test25::V::f() -// CHECK-NEXT: 5 | void Test25::C::g() -// CHECK-NEXT: 6 | vbase_offset (-8) -// CHECK-NEXT: 7 | vcall_offset (-8) -// CHECK-NEXT: 8 | offset_to_top (-8) -// CHECK-NEXT: 9 | Test25::C RTTI -// CHECK-NEXT: -- (Test25::B, 8) vtable address -- -// CHECK-NEXT: 10 | [unused] void Test25::V::f() - -// CHECK: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vcall_offset (0) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test25::A RTTI -// CHECK-NEXT: -- (Test25::A, 0) vtable address -- -// CHECK-NEXT: -- (Test25::V, 0) vtable address -- -// CHECK-NEXT: 4 | void Test25::V::f() - -// CHECK: Construction vtable for ('Test25::B', 8) in 'Test25::C' (9 entries). -// CHECK-NEXT: 0 | vbase_offset (-8) -// CHECK-NEXT: 1 | vcall_offset (-8) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test25::B RTTI -// CHECK-NEXT: -- (Test25::B, 8) vtable address -- -// CHECK-NEXT: 4 | [unused] void Test25::V::f() -// CHECK-NEXT: 5 | vcall_offset (0) -// CHECK-NEXT: 6 | offset_to_top (8) -// CHECK-NEXT: 7 | Test25::B RTTI -// CHECK-NEXT: -- (Test25::V, 0) vtable address -- -// CHECK-NEXT: 8 | void Test25::V::f() +// CHECK-32: Vtable for 'Test25::C' (11 entries). +// CHECK-32-NEXT: 0 | vbase_offset (0) +// CHECK-32-NEXT: 1 | vcall_offset (0) +// CHECK-32-NEXT: 2 | offset_to_top (0) +// CHECK-32-NEXT: 3 | Test25::C RTTI +// CHECK-32-NEXT: -- (Test25::A, 0) vtable address -- +// CHECK-32-NEXT: -- (Test25::C, 0) vtable address -- +// CHECK-32-NEXT: -- (Test25::V, 0) vtable address -- +// CHECK-32-NEXT: 4 | void Test25::V::f() +// CHECK-32-NEXT: 5 | void Test25::C::g() +// CHECK-32-NEXT: 6 | vbase_offset (-8) +// CHECK-32-NEXT: 7 | vcall_offset (-8) +// CHECK-32-NEXT: 8 | offset_to_top (-8) +// CHECK-32-NEXT: 9 | Test25::C RTTI +// CHECK-32-NEXT: -- (Test25::B, 8) vtable address -- +// CHECK-32-NEXT: 10 | [unused] void Test25::V::f() + +// CHECK-32: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries). +// CHECK-32-NEXT: 0 | vbase_offset (0) +// CHECK-32-NEXT: 1 | vcall_offset (0) +// CHECK-32-NEXT: 2 | offset_to_top (0) +// CHECK-32-NEXT: 3 | Test25::A RTTI +// CHECK-32-NEXT: -- (Test25::A, 0) vtable address -- +// CHECK-32-NEXT: -- (Test25::V, 0) vtable address -- +// CHECK-32-NEXT: 4 | void Test25::V::f() + +// CHECK-32: Construction vtable for ('Test25::B', 8) in 'Test25::C' (9 entries). +// CHECK-32-NEXT: 0 | vbase_offset (-8) +// CHECK-32-NEXT: 1 | vcall_offset (-8) +// CHECK-32-NEXT: 2 | offset_to_top (0) +// CHECK-32-NEXT: 3 | Test25::B RTTI +// CHECK-32-NEXT: -- (Test25::B, 8) vtable address -- +// CHECK-32-NEXT: 4 | [unused] void Test25::V::f() +// CHECK-32-NEXT: 5 | vcall_offset (0) +// CHECK-32-NEXT: 6 | offset_to_top (8) +// CHECK-32-NEXT: 7 | Test25::B RTTI +// CHECK-32-NEXT: -- (Test25::V, 0) vtable address -- +// CHECK-32-NEXT: 8 | void Test25::V::f() struct C : A, virtual V, B { virtual void g(); }; @@ -1109,37 +1151,37 @@ struct C : virtual A { virtual void b(); }; -// CHECK: Vtable for 'Test26::D' (15 entries). -// CHECK-NEXT: 0 | vbase_offset (8) -// CHECK-NEXT: 1 | vbase_offset (8) -// CHECK-NEXT: 2 | vbase_offset (0) -// CHECK-NEXT: 3 | vcall_offset (0) -// CHECK-NEXT: 4 | offset_to_top (0) -// CHECK-NEXT: 5 | Test26::D RTTI -// CHECK-NEXT: -- (Test26::B, 0) vtable address -- -// CHECK-NEXT: -- (Test26::D, 0) vtable address -- -// CHECK-NEXT: 6 | void Test26::B::c() -// CHECK-NEXT: 7 | void Test26::D::d() -// CHECK-NEXT: 8 | vcall_offset (0) -// CHECK-NEXT: 9 | vbase_offset (0) -// CHECK-NEXT: 10 | vcall_offset (0) -// CHECK-NEXT: 11 | offset_to_top (-8) -// CHECK-NEXT: 12 | Test26::D RTTI -// CHECK-NEXT: -- (Test26::A, 8) vtable address -- -// CHECK-NEXT: -- (Test26::C, 8) vtable address -- -// CHECK-NEXT: 13 | void Test26::A::a() -// CHECK-NEXT: 14 | void Test26::C::b() - -// CHECK: Construction vtable for ('Test26::C', 8) in 'Test26::D' (7 entries). -// CHECK-NEXT: 0 | vcall_offset (0) -// CHECK-NEXT: 1 | vbase_offset (0) -// CHECK-NEXT: 2 | vcall_offset (0) -// CHECK-NEXT: 3 | offset_to_top (0) -// CHECK-NEXT: 4 | Test26::C RTTI -// CHECK-NEXT: -- (Test26::A, 8) vtable address -- -// CHECK-NEXT: -- (Test26::C, 8) vtable address -- -// CHECK-NEXT: 5 | void Test26::A::a() -// CHECK-NEXT: 6 | void Test26::C::b() +// CHECK-33: Vtable for 'Test26::D' (15 entries). +// CHECK-33-NEXT: 0 | vbase_offset (8) +// CHECK-33-NEXT: 1 | vbase_offset (8) +// CHECK-33-NEXT: 2 | vbase_offset (0) +// CHECK-33-NEXT: 3 | vcall_offset (0) +// CHECK-33-NEXT: 4 | offset_to_top (0) +// CHECK-33-NEXT: 5 | Test26::D RTTI +// CHECK-33-NEXT: -- (Test26::B, 0) vtable address -- +// CHECK-33-NEXT: -- (Test26::D, 0) vtable address -- +// CHECK-33-NEXT: 6 | void Test26::B::c() +// CHECK-33-NEXT: 7 | void Test26::D::d() +// CHECK-33-NEXT: 8 | vcall_offset (0) +// CHECK-33-NEXT: 9 | vbase_offset (0) +// CHECK-33-NEXT: 10 | vcall_offset (0) +// CHECK-33-NEXT: 11 | offset_to_top (-8) +// CHECK-33-NEXT: 12 | Test26::D RTTI +// CHECK-33-NEXT: -- (Test26::A, 8) vtable address -- +// CHECK-33-NEXT: -- (Test26::C, 8) vtable address -- +// CHECK-33-NEXT: 13 | void Test26::A::a() +// CHECK-33-NEXT: 14 | void Test26::C::b() + +// CHECK-33: Construction vtable for ('Test26::C', 8) in 'Test26::D' (7 entries). +// CHECK-33-NEXT: 0 | vcall_offset (0) +// CHECK-33-NEXT: 1 | vbase_offset (0) +// CHECK-33-NEXT: 2 | vcall_offset (0) +// CHECK-33-NEXT: 3 | offset_to_top (0) +// CHECK-33-NEXT: 4 | Test26::C RTTI +// CHECK-33-NEXT: -- (Test26::A, 8) vtable address -- +// CHECK-33-NEXT: -- (Test26::C, 8) vtable address -- +// CHECK-33-NEXT: 5 | void Test26::A::a() +// CHECK-33-NEXT: 6 | void Test26::C::b() class D : virtual B, virtual C { virtual void d(); }; @@ -1168,39 +1210,39 @@ 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() +// CHECK-34: Vtable for 'Test27::E' (13 entries). +// CHECK-34-NEXT: 0 | vbase_offset (16) +// CHECK-34-NEXT: 1 | offset_to_top (0) +// CHECK-34-NEXT: 2 | Test27::E RTTI +// CHECK-34-NEXT: -- (Test27::A, 0) vtable address -- +// CHECK-34-NEXT: -- (Test27::D, 0) vtable address -- +// CHECK-34-NEXT: -- (Test27::E, 0) vtable address -- +// CHECK-34-NEXT: 3 | void Test27::A::a() +// CHECK-34-NEXT: 4 | void Test27::D::d() +// CHECK-34-NEXT: 5 | void Test27::E::e() +// CHECK-34-NEXT: 6 | offset_to_top (-8) +// CHECK-34-NEXT: 7 | Test27::E RTTI +// CHECK-34-NEXT: -- (Test27::C, 8) vtable address -- +// CHECK-34-NEXT: 8 | void Test27::C::c() +// CHECK-34-NEXT: 9 | vcall_offset (0) +// CHECK-34-NEXT: 10 | offset_to_top (-16) +// CHECK-34-NEXT: 11 | Test27::E RTTI +// CHECK-34-NEXT: -- (Test27::B, 16) vtable address -- +// CHECK-34-NEXT: 12 | void Test27::B::b() + +// CHECK-34: Construction vtable for ('Test27::D', 0) in 'Test27::E' (9 entries). +// CHECK-34-NEXT: 0 | vbase_offset (16) +// CHECK-34-NEXT: 1 | offset_to_top (0) +// CHECK-34-NEXT: 2 | Test27::D RTTI +// CHECK-34-NEXT: -- (Test27::A, 0) vtable address -- +// CHECK-34-NEXT: -- (Test27::D, 0) vtable address -- +// CHECK-34-NEXT: 3 | void Test27::A::a() +// CHECK-34-NEXT: 4 | void Test27::D::d() +// CHECK-34-NEXT: 5 | vcall_offset (0) +// CHECK-34-NEXT: 6 | offset_to_top (-16) +// CHECK-34-NEXT: 7 | Test27::D RTTI +// CHECK-34-NEXT: -- (Test27::B, 16) vtable address -- +// CHECK-34-NEXT: 8 | void Test27::B::b() struct E : D { virtual void e(); }; @@ -1228,45 +1270,45 @@ struct C : A, B { 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() +// CHECK-35: Vtable for 'Test28::E' (14 entries). +// CHECK-35-NEXT: 0 | vbase_offset (8) +// CHECK-35-NEXT: 1 | offset_to_top (0) +// CHECK-35-NEXT: 2 | Test28::E RTTI +// CHECK-35-NEXT: -- (Test28::D, 0) vtable address -- +// CHECK-35-NEXT: -- (Test28::E, 0) vtable address -- +// CHECK-35-NEXT: 3 | void Test28::E::e() +// CHECK-35-NEXT: 4 | vcall_offset (8) +// CHECK-35-NEXT: 5 | vcall_offset (0) +// CHECK-35-NEXT: 6 | vcall_offset (0) +// CHECK-35-NEXT: 7 | offset_to_top (-8) +// CHECK-35-NEXT: 8 | Test28::E RTTI +// CHECK-35-NEXT: -- (Test28::A, 8) vtable address -- +// CHECK-35-NEXT: -- (Test28::C, 8) vtable address -- +// CHECK-35-NEXT: 9 | void Test28::A::a() +// CHECK-35-NEXT: 10 | void Test28::C::c() +// CHECK-35-NEXT: 11 | offset_to_top (-16) +// CHECK-35-NEXT: 12 | Test28::E RTTI +// CHECK-35-NEXT: -- (Test28::B, 16) vtable address -- +// CHECK-35-NEXT: 13 | void Test28::B::b() + +// CHECK-35: Construction vtable for ('Test28::D', 0) in 'Test28::E' (13 entries). +// CHECK-35-NEXT: 0 | vbase_offset (8) +// CHECK-35-NEXT: 1 | offset_to_top (0) +// CHECK-35-NEXT: 2 | Test28::D RTTI +// CHECK-35-NEXT: -- (Test28::D, 0) vtable address -- +// CHECK-35-NEXT: 3 | vcall_offset (8) +// CHECK-35-NEXT: 4 | vcall_offset (0) +// CHECK-35-NEXT: 5 | vcall_offset (0) +// CHECK-35-NEXT: 6 | offset_to_top (-8) +// CHECK-35-NEXT: 7 | Test28::D RTTI +// CHECK-35-NEXT: -- (Test28::A, 8) vtable address -- +// CHECK-35-NEXT: -- (Test28::C, 8) vtable address -- +// CHECK-35-NEXT: 8 | void Test28::A::a() +// CHECK-35-NEXT: 9 | void Test28::C::c() +// CHECK-35-NEXT: 10 | offset_to_top (-16) +// CHECK-35-NEXT: 11 | Test28::D RTTI +// CHECK-35-NEXT: -- (Test28::B, 16) vtable address -- +// CHECK-35-NEXT: 12 | void Test28::B::b() struct E : D { virtual void e(); }; @@ -1286,17 +1328,17 @@ struct A { virtual V1 *f(); }; -// CHECK: Vtable for 'Test29::B' (6 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vcall_offset (0) -// CHECK-NEXT: 2 | offset_to_top (0) -// CHECK-NEXT: 3 | Test29::B RTTI -// CHECK-NEXT: -- (Test29::A, 0) vtable address -- -// CHECK-NEXT: -- (Test29::B, 0) vtable address -- -// CHECK-NEXT: 4 | Test29::V2 *Test29::B::f() -// CHECK-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset] -// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] -// CHECK-NEXT: 5 | Test29::V2 *Test29::B::f() +// CHECK-36: Vtable for 'Test29::B' (6 entries). +// CHECK-36-NEXT: 0 | vbase_offset (0) +// CHECK-36-NEXT: 1 | vcall_offset (0) +// CHECK-36-NEXT: 2 | offset_to_top (0) +// CHECK-36-NEXT: 3 | Test29::B RTTI +// CHECK-36-NEXT: -- (Test29::A, 0) vtable address -- +// CHECK-36-NEXT: -- (Test29::B, 0) vtable address -- +// CHECK-36-NEXT: 4 | Test29::V2 *Test29::B::f() +// CHECK-36-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset] +// CHECK-36-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-36-NEXT: 5 | Test29::V2 *Test29::B::f() struct B : virtual A { virtual V2 *f(); }; @@ -1342,22 +1384,22 @@ struct C : A, virtual B { virtual void f(); }; -// CHECK: Vtable for 'Test31::D' (11 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vbase_offset (8) -// CHECK-NEXT: 2 | vcall_offset (0) -// CHECK-NEXT: 3 | offset_to_top (0) -// CHECK-NEXT: 4 | Test31::D RTTI -// CHECK-NEXT: -- (Test31::B, 0) vtable address -- -// CHECK-NEXT: -- (Test31::D, 0) vtable address -- -// CHECK-NEXT: 5 | void Test31::D::f() -// CHECK-NEXT: 6 | vbase_offset (-8) -// CHECK-NEXT: 7 | vcall_offset (-8) -// CHECK-NEXT: 8 | offset_to_top (-8) -// CHECK-NEXT: 9 | Test31::D RTTI -// CHECK-NEXT: -- (Test31::C, 8) vtable address -- -// CHECK-NEXT: 10 | void Test31::D::f() -// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-37: Vtable for 'Test31::D' (11 entries). +// CHECK-37-NEXT: 0 | vbase_offset (0) +// CHECK-37-NEXT: 1 | vbase_offset (8) +// CHECK-37-NEXT: 2 | vcall_offset (0) +// CHECK-37-NEXT: 3 | offset_to_top (0) +// CHECK-37-NEXT: 4 | Test31::D RTTI +// CHECK-37-NEXT: -- (Test31::B, 0) vtable address -- +// CHECK-37-NEXT: -- (Test31::D, 0) vtable address -- +// CHECK-37-NEXT: 5 | void Test31::D::f() +// CHECK-37-NEXT: 6 | vbase_offset (-8) +// CHECK-37-NEXT: 7 | vcall_offset (-8) +// CHECK-37-NEXT: 8 | offset_to_top (-8) +// CHECK-37-NEXT: 9 | Test31::D RTTI +// CHECK-37-NEXT: -- (Test31::C, 8) vtable address -- +// CHECK-37-NEXT: 10 | void Test31::D::f() +// CHECK-37-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] struct D : virtual C { virtual void f(); }; @@ -1377,10 +1419,10 @@ struct B : virtual A { }; struct C : A, virtual B { }; struct D : virtual B { }; -// CHECK: Virtual base offset offsets for 'Test32::E' (3 entries). -// CHECK-NEXT: Test32::A | -32 -// CHECK-NEXT: Test32::B | -24 -// CHECK-NEXT: Test32::D | -40 +// CHECK-38: Virtual base offset offsets for 'Test32::E' (3 entries). +// CHECK-38-NEXT: Test32::A | -32 +// CHECK-38-NEXT: Test32::B | -24 +// CHECK-38-NEXT: Test32::D | -40 struct E : C, virtual D { virtual void f(); }; @@ -1410,45 +1452,45 @@ struct E : A, D { virtual void e(); }; -// CHECK: Vtable for 'Test33::F' (30 entries). -// CHECK-NEXT: 0 | vbase_offset (24) -// CHECK-NEXT: 1 | vbase_offset (16) -// CHECK-NEXT: 2 | vbase_offset (16) -// CHECK-NEXT: 3 | vbase_offset (8) -// CHECK-NEXT: 4 | offset_to_top (0) -// CHECK-NEXT: 5 | Test33::F RTTI -// CHECK-NEXT: -- (Test33::A, 0) vtable address -- -// CHECK-NEXT: -- (Test33::F, 0) vtable address -- -// CHECK-NEXT: 6 | void Test33::A::a() -// CHECK-NEXT: 7 | void Test33::F::f() -// CHECK-NEXT: 8 | vcall_offset (0) -// CHECK-NEXT: 9 | vcall_offset (0) -// CHECK-NEXT: 10 | vbase_offset (16) -// CHECK-NEXT: 11 | vbase_offset (8) -// CHECK-NEXT: 12 | vbase_offset (8) -// CHECK-NEXT: 13 | offset_to_top (-8) -// CHECK-NEXT: 14 | Test33::F RTTI -// CHECK-NEXT: -- (Test33::A, 8) vtable address -- -// CHECK-NEXT: -- (Test33::E, 8) vtable address -- -// CHECK-NEXT: 15 | void Test33::A::a() -// CHECK-NEXT: 16 | void Test33::E::e() -// CHECK-NEXT: 17 | vbase_offset (0) -// CHECK-NEXT: 18 | vcall_offset (0) -// CHECK-NEXT: 19 | vbase_offset (8) -// CHECK-NEXT: 20 | vbase_offset (0) -// CHECK-NEXT: 21 | vcall_offset (0) -// CHECK-NEXT: 22 | offset_to_top (-16) -// CHECK-NEXT: 23 | Test33::F RTTI -// CHECK-NEXT: -- (Test33::A, 16) vtable address -- -// CHECK-NEXT: -- (Test33::C, 16) vtable address -- -// CHECK-NEXT: -- (Test33::D, 16) vtable address -- -// CHECK-NEXT: 24 | void Test33::A::a() -// CHECK-NEXT: 25 | void Test33::C::c() -// CHECK-NEXT: 26 | vcall_offset (0) -// CHECK-NEXT: 27 | offset_to_top (-24) -// CHECK-NEXT: 28 | Test33::F RTTI -// CHECK-NEXT: -- (Test33::B, 24) vtable address -- -// CHECK-NEXT: 29 | void Test33::B::b() +// CHECK-39: Vtable for 'Test33::F' (30 entries). +// CHECK-39-NEXT: 0 | vbase_offset (24) +// CHECK-39-NEXT: 1 | vbase_offset (16) +// CHECK-39-NEXT: 2 | vbase_offset (16) +// CHECK-39-NEXT: 3 | vbase_offset (8) +// CHECK-39-NEXT: 4 | offset_to_top (0) +// CHECK-39-NEXT: 5 | Test33::F RTTI +// CHECK-39-NEXT: -- (Test33::A, 0) vtable address -- +// CHECK-39-NEXT: -- (Test33::F, 0) vtable address -- +// CHECK-39-NEXT: 6 | void Test33::A::a() +// CHECK-39-NEXT: 7 | void Test33::F::f() +// CHECK-39-NEXT: 8 | vcall_offset (0) +// CHECK-39-NEXT: 9 | vcall_offset (0) +// CHECK-39-NEXT: 10 | vbase_offset (16) +// CHECK-39-NEXT: 11 | vbase_offset (8) +// CHECK-39-NEXT: 12 | vbase_offset (8) +// CHECK-39-NEXT: 13 | offset_to_top (-8) +// CHECK-39-NEXT: 14 | Test33::F RTTI +// CHECK-39-NEXT: -- (Test33::A, 8) vtable address -- +// CHECK-39-NEXT: -- (Test33::E, 8) vtable address -- +// CHECK-39-NEXT: 15 | void Test33::A::a() +// CHECK-39-NEXT: 16 | void Test33::E::e() +// CHECK-39-NEXT: 17 | vbase_offset (0) +// CHECK-39-NEXT: 18 | vcall_offset (0) +// CHECK-39-NEXT: 19 | vbase_offset (8) +// CHECK-39-NEXT: 20 | vbase_offset (0) +// CHECK-39-NEXT: 21 | vcall_offset (0) +// CHECK-39-NEXT: 22 | offset_to_top (-16) +// CHECK-39-NEXT: 23 | Test33::F RTTI +// CHECK-39-NEXT: -- (Test33::A, 16) vtable address -- +// CHECK-39-NEXT: -- (Test33::C, 16) vtable address -- +// CHECK-39-NEXT: -- (Test33::D, 16) vtable address -- +// CHECK-39-NEXT: 24 | void Test33::A::a() +// CHECK-39-NEXT: 25 | void Test33::C::c() +// CHECK-39-NEXT: 26 | vcall_offset (0) +// CHECK-39-NEXT: 27 | offset_to_top (-24) +// CHECK-39-NEXT: 28 | Test33::F RTTI +// CHECK-39-NEXT: -- (Test33::B, 24) vtable address -- +// CHECK-39-NEXT: 29 | void Test33::B::b() struct F : virtual E, A { virtual void f(); }; @@ -1475,36 +1517,36 @@ struct E : virtual D { virtual void e(); }; -// CHECK: Construction vtable for ('Test34::E', 0) in 'Test34::F' (22 entries). -// CHECK-NEXT: 0 | vbase_offset (0) -// CHECK-NEXT: 1 | vbase_offset (8) -// CHECK-NEXT: 2 | vcall_offset (0) -// CHECK-NEXT: 3 | offset_to_top (0) -// CHECK-NEXT: 4 | Test34::E RTTI -// CHECK-NEXT: -- (Test34::A, 0) vtable address -- -// CHECK-NEXT: -- (Test34::E, 0) vtable address -- -// CHECK-NEXT: 5 | void Test34::A::a() -// CHECK-NEXT: 6 | void Test34::E::e() -// CHECK-NEXT: 7 | vcall_offset (8) -// CHECK-NEXT: 8 | vcall_offset (0) -// CHECK-NEXT: 9 | vbase_offset (-8) -// CHECK-NEXT: 10 | offset_to_top (-8) -// CHECK-NEXT: 11 | Test34::E RTTI -// CHECK-NEXT: -- (Test34::A, 8) vtable address -- -// CHECK-NEXT: -- (Test34::D, 8) vtable address -- -// CHECK-NEXT: 12 | void Test34::A::a() -// CHECK-NEXT: 13 | vbase_offset (-16) -// CHECK-NEXT: 14 | vcall_offset (-16) -// CHECK-NEXT: 15 | offset_to_top (-16) -// CHECK-NEXT: 16 | Test34::E RTTI -// CHECK-NEXT: -- (Test34::B, 16) vtable address -- -// CHECK-NEXT: -- (Test34::C, 16) vtable address -- -// CHECK-NEXT: 17 | [unused] void Test34::A::a() -// CHECK-NEXT: 18 | void Test34::C::c() -// CHECK-NEXT: 19 | offset_to_top (-24) -// CHECK-NEXT: 20 | Test34::E RTTI -// CHECK-NEXT: -- (Test34::A, 24) vtable address -- -// CHECK-NEXT: 21 | void Test34::A::a() +// CHECK-40: Construction vtable for ('Test34::E', 0) in 'Test34::F' (22 entries). +// CHECK-40-NEXT: 0 | vbase_offset (0) +// CHECK-40-NEXT: 1 | vbase_offset (8) +// CHECK-40-NEXT: 2 | vcall_offset (0) +// CHECK-40-NEXT: 3 | offset_to_top (0) +// CHECK-40-NEXT: 4 | Test34::E RTTI +// CHECK-40-NEXT: -- (Test34::A, 0) vtable address -- +// CHECK-40-NEXT: -- (Test34::E, 0) vtable address -- +// CHECK-40-NEXT: 5 | void Test34::A::a() +// CHECK-40-NEXT: 6 | void Test34::E::e() +// CHECK-40-NEXT: 7 | vcall_offset (8) +// CHECK-40-NEXT: 8 | vcall_offset (0) +// CHECK-40-NEXT: 9 | vbase_offset (-8) +// CHECK-40-NEXT: 10 | offset_to_top (-8) +// CHECK-40-NEXT: 11 | Test34::E RTTI +// CHECK-40-NEXT: -- (Test34::A, 8) vtable address -- +// CHECK-40-NEXT: -- (Test34::D, 8) vtable address -- +// CHECK-40-NEXT: 12 | void Test34::A::a() +// CHECK-40-NEXT: 13 | vbase_offset (-16) +// CHECK-40-NEXT: 14 | vcall_offset (-16) +// CHECK-40-NEXT: 15 | offset_to_top (-16) +// CHECK-40-NEXT: 16 | Test34::E RTTI +// CHECK-40-NEXT: -- (Test34::B, 16) vtable address -- +// CHECK-40-NEXT: -- (Test34::C, 16) vtable address -- +// CHECK-40-NEXT: 17 | [unused] void Test34::A::a() +// CHECK-40-NEXT: 18 | void Test34::C::c() +// CHECK-40-NEXT: 19 | offset_to_top (-24) +// CHECK-40-NEXT: 20 | Test34::E RTTI +// CHECK-40-NEXT: -- (Test34::A, 24) vtable address -- +// CHECK-40-NEXT: 21 | void Test34::A::a() struct F : E { virtual void f(); }; @@ -1543,55 +1585,55 @@ struct E : D { struct F : virtual D { }; struct G : virtual E { }; -// CHECK: Vtable for 'Test35::H' (32 entries). -// CHECK-NEXT: 0 | vbase_offset (32) -// CHECK-NEXT: 1 | vbase_offset (0) -// CHECK-NEXT: 2 | vcall_offset (0) -// CHECK-NEXT: 3 | vcall_offset (0) -// CHECK-NEXT: 4 | vbase_offset (16) -// CHECK-NEXT: 5 | vbase_offset (8) -// CHECK-NEXT: 6 | offset_to_top (0) -// CHECK-NEXT: 7 | Test35::H RTTI -// CHECK-NEXT: -- (Test35::C, 0) vtable address -- -// CHECK-NEXT: -- (Test35::D, 0) vtable address -- -// CHECK-NEXT: -- (Test35::F, 0) vtable address -- -// CHECK-NEXT: -- (Test35::H, 0) vtable address -- -// CHECK-NEXT: 8 | void Test35::C::c() -// CHECK-NEXT: 9 | void Test35::D::d() -// CHECK-NEXT: 10 | void Test35::H::h() -// CHECK-NEXT: 11 | vbase_offset (0) -// CHECK-NEXT: 12 | vbase_offset (24) -// CHECK-NEXT: 13 | vcall_offset (0) -// CHECK-NEXT: 14 | vbase_offset (8) -// CHECK-NEXT: 15 | offset_to_top (-8) -// CHECK-NEXT: 16 | Test35::H RTTI -// CHECK-NEXT: -- (Test35::B, 8) vtable address -- -// CHECK-NEXT: -- (Test35::G, 8) vtable address -- -// CHECK-NEXT: 17 | void Test35::B::b() -// CHECK-NEXT: 18 | vcall_offset (0) -// CHECK-NEXT: 19 | offset_to_top (-16) -// CHECK-NEXT: 20 | Test35::H RTTI -// CHECK-NEXT: -- (Test35::A, 16) vtable address -- -// CHECK-NEXT: 21 | void Test35::A::a() -// CHECK-NEXT: 22 | vcall_offset (0) -// CHECK-NEXT: 23 | vcall_offset (0) -// CHECK-NEXT: 24 | vcall_offset (0) -// CHECK-NEXT: 25 | vbase_offset (-16) -// CHECK-NEXT: 26 | vbase_offset (-24) -// CHECK-NEXT: 27 | offset_to_top (-32) -// CHECK-NEXT: 28 | Test35::H RTTI -// CHECK-NEXT: -- (Test35::C, 32) vtable address -- -// CHECK-NEXT: -- (Test35::D, 32) vtable address -- -// CHECK-NEXT: -- (Test35::E, 32) vtable address -- -// CHECK-NEXT: 29 | void Test35::C::c() -// CHECK-NEXT: 30 | void Test35::D::d() -// CHECK-NEXT: 31 | void Test35::E::e() - -// CHECK: Virtual base offset offsets for 'Test35::H' (4 entries). -// CHECK-NEXT: Test35::A | -32 -// CHECK-NEXT: Test35::B | -24 -// CHECK-NEXT: Test35::D | -56 -// CHECK-NEXT: Test35::E | -64 +// CHECK-41: Vtable for 'Test35::H' (32 entries). +// CHECK-41-NEXT: 0 | vbase_offset (32) +// CHECK-41-NEXT: 1 | vbase_offset (0) +// CHECK-41-NEXT: 2 | vcall_offset (0) +// CHECK-41-NEXT: 3 | vcall_offset (0) +// CHECK-41-NEXT: 4 | vbase_offset (16) +// CHECK-41-NEXT: 5 | vbase_offset (8) +// CHECK-41-NEXT: 6 | offset_to_top (0) +// CHECK-41-NEXT: 7 | Test35::H RTTI +// CHECK-41-NEXT: -- (Test35::C, 0) vtable address -- +// CHECK-41-NEXT: -- (Test35::D, 0) vtable address -- +// CHECK-41-NEXT: -- (Test35::F, 0) vtable address -- +// CHECK-41-NEXT: -- (Test35::H, 0) vtable address -- +// CHECK-41-NEXT: 8 | void Test35::C::c() +// CHECK-41-NEXT: 9 | void Test35::D::d() +// CHECK-41-NEXT: 10 | void Test35::H::h() +// CHECK-41-NEXT: 11 | vbase_offset (0) +// CHECK-41-NEXT: 12 | vbase_offset (24) +// CHECK-41-NEXT: 13 | vcall_offset (0) +// CHECK-41-NEXT: 14 | vbase_offset (8) +// CHECK-41-NEXT: 15 | offset_to_top (-8) +// CHECK-41-NEXT: 16 | Test35::H RTTI +// CHECK-41-NEXT: -- (Test35::B, 8) vtable address -- +// CHECK-41-NEXT: -- (Test35::G, 8) vtable address -- +// CHECK-41-NEXT: 17 | void Test35::B::b() +// CHECK-41-NEXT: 18 | vcall_offset (0) +// CHECK-41-NEXT: 19 | offset_to_top (-16) +// CHECK-41-NEXT: 20 | Test35::H RTTI +// CHECK-41-NEXT: -- (Test35::A, 16) vtable address -- +// CHECK-41-NEXT: 21 | void Test35::A::a() +// CHECK-41-NEXT: 22 | vcall_offset (0) +// CHECK-41-NEXT: 23 | vcall_offset (0) +// CHECK-41-NEXT: 24 | vcall_offset (0) +// CHECK-41-NEXT: 25 | vbase_offset (-16) +// CHECK-41-NEXT: 26 | vbase_offset (-24) +// CHECK-41-NEXT: 27 | offset_to_top (-32) +// CHECK-41-NEXT: 28 | Test35::H RTTI +// CHECK-41-NEXT: -- (Test35::C, 32) vtable address -- +// CHECK-41-NEXT: -- (Test35::D, 32) vtable address -- +// CHECK-41-NEXT: -- (Test35::E, 32) vtable address -- +// CHECK-41-NEXT: 29 | void Test35::C::c() +// CHECK-41-NEXT: 30 | void Test35::D::d() +// CHECK-41-NEXT: 31 | void Test35::E::e() + +// CHECK-41: Virtual base offset offsets for 'Test35::H' (4 entries). +// CHECK-41-NEXT: Test35::A | -32 +// CHECK-41-NEXT: Test35::B | -24 +// CHECK-41-NEXT: Test35::D | -56 +// CHECK-41-NEXT: Test35::E | -64 struct H : F, G { virtual void h(); }; @@ -1613,24 +1655,24 @@ struct C : virtual A { virtual void f(); }; -// CHECK: Vtable for 'Test36::D' (12 entries). -// CHECK-NEXT: 0 | vbase_offset (8) -// CHECK-NEXT: 1 | vbase_offset (8) -// CHECK-NEXT: 2 | vcall_offset (0) -// CHECK-NEXT: 3 | offset_to_top (0) -// CHECK-NEXT: 4 | Test36::D RTTI -// CHECK-NEXT: -- (Test36::C, 0) vtable address -- -// CHECK-NEXT: -- (Test36::D, 0) vtable address -- -// CHECK-NEXT: 5 | void Test36::C::f() -// CHECK-NEXT: 6 | void Test36::D::g() -// CHECK-NEXT: 7 | vbase_offset (0) -// CHECK-NEXT: 8 | vcall_offset (-8) -// CHECK-NEXT: 9 | offset_to_top (-8) -// CHECK-NEXT: 10 | Test36::D RTTI -// CHECK-NEXT: -- (Test36::A, 8) vtable address -- -// CHECK-NEXT: -- (Test36::B, 8) vtable address -- -// CHECK-NEXT: 11 | void Test36::C::f() -// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-42: Vtable for 'Test36::D' (12 entries). +// CHECK-42-NEXT: 0 | vbase_offset (8) +// CHECK-42-NEXT: 1 | vbase_offset (8) +// CHECK-42-NEXT: 2 | vcall_offset (0) +// CHECK-42-NEXT: 3 | offset_to_top (0) +// CHECK-42-NEXT: 4 | Test36::D RTTI +// CHECK-42-NEXT: -- (Test36::C, 0) vtable address -- +// CHECK-42-NEXT: -- (Test36::D, 0) vtable address -- +// CHECK-42-NEXT: 5 | void Test36::C::f() +// CHECK-42-NEXT: 6 | void Test36::D::g() +// CHECK-42-NEXT: 7 | vbase_offset (0) +// CHECK-42-NEXT: 8 | vcall_offset (-8) +// CHECK-42-NEXT: 9 | offset_to_top (-8) +// CHECK-42-NEXT: 10 | Test36::D RTTI +// CHECK-42-NEXT: -- (Test36::A, 8) vtable address -- +// CHECK-42-NEXT: -- (Test36::B, 8) vtable address -- +// CHECK-42-NEXT: 11 | void Test36::C::f() +// CHECK-42-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] struct D : virtual B, C { virtual void g(); }; diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp index c75efe228dff..b3b68703c6d3 100644 --- a/test/CodeGenCXX/vtable-linkage.cpp +++ b/test/CodeGenCXX/vtable-linkage.cpp @@ -1,4 +1,16 @@ -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o %t +// RUN: FileCheck --check-prefix=CHECK-1 %s < %t +// RUN: FileCheck --check-prefix=CHECK-2 %s < %t +// RUN: FileCheck --check-prefix=CHECK-3 %s < %t +// RUN: FileCheck --check-prefix=CHECK-4 %s < %t +// RUN: FileCheck --check-prefix=CHECK-5 %s < %t +// RUN: FileCheck --check-prefix=CHECK-6 %s < %t +// RUN: FileCheck --check-prefix=CHECK-7 %s < %t +// RUN: FileCheck --check-prefix=CHECK-8 %s < %t +// RUN: FileCheck --check-prefix=CHECK-9 %s < %t +// RUN: FileCheck --check-prefix=CHECK-10 %s < %t +// RUN: FileCheck --check-prefix=CHECK-11 %s < %t +// RUN: FileCheck --check-prefix=CHECK-12 %s < %t namespace { struct A { @@ -73,7 +85,7 @@ extern template struct F<int>; void use_F(F<char> &fc) { F<int> fi; - (void)fi; + fi.foo(); F<long> fl; (void)fl; fc.foo(); @@ -81,71 +93,85 @@ void use_F(F<char> &fc) { // B has a key function that is not defined in this translation unit so its vtable // has external linkage. -// CHECK: @_ZTV1B = external constant +// CHECK-1: @_ZTV1B = external constant // C has no key function, so its vtable should have weak_odr linkage. -// CHECK: @_ZTV1C = weak_odr constant -// CHECK: @_ZTS1C = weak_odr constant -// CHECK: @_ZTI1C = weak_odr constant +// CHECK-2: @_ZTV1C = weak_odr constant +// CHECK-2: @_ZTS1C = weak_odr constant +// CHECK-2: @_ZTI1C = weak_odr constant // D has a key function that is defined in this translation unit so its vtable is // defined in the translation unit. -// CHECK: @_ZTV1D = constant -// CHECK: @_ZTS1D = constant -// CHECK: @_ZTI1D = constant +// CHECK-3: @_ZTV1D = constant +// CHECK-3: @_ZTS1D = constant +// CHECK-3: @_ZTI1D = constant // E<char> is an explicit specialization with a key function defined // in this translation unit, so its vtable should have external // linkage. -// CHECK: @_ZTV1EIcE = constant -// CHECK: @_ZTS1EIcE = constant -// CHECK: @_ZTI1EIcE = constant +// CHECK-4: @_ZTV1EIcE = constant +// CHECK-4: @_ZTS1EIcE = constant +// CHECK-4: @_ZTI1EIcE = constant // E<short> is an explicit template instantiation with a key function // defined in this translation unit, so its vtable should have // weak_odr linkage. -// CHECK: @_ZTV1EIsE = weak_odr constant -// CHECK: @_ZTS1EIsE = weak_odr constant -// CHECK: @_ZTI1EIsE = weak_odr constant +// CHECK-5: @_ZTV1EIsE = weak_odr constant +// CHECK-5: @_ZTS1EIsE = weak_odr constant +// CHECK-5: @_ZTI1EIsE = weak_odr constant // F<short> is an explicit template instantiation without a key // function, so its vtable should have weak_odr linkage -// CHECK: @_ZTV1FIsE = weak_odr constant -// CHECK: @_ZTS1FIsE = weak_odr constant -// CHECK: @_ZTI1FIsE = weak_odr constant +// CHECK-6: @_ZTV1FIsE = weak_odr constant +// CHECK-6: @_ZTS1FIsE = weak_odr constant +// CHECK-6: @_ZTI1FIsE = weak_odr constant // E<long> is an implicit template instantiation with a key function // defined in this translation unit, so its vtable should have // weak_odr linkage. -// CHECK: @_ZTV1EIlE = weak_odr constant -// CHECK: @_ZTS1EIlE = weak_odr constant -// CHECK: @_ZTI1EIlE = weak_odr constant +// CHECK-7: @_ZTV1EIlE = weak_odr constant +// CHECK-7: @_ZTS1EIlE = weak_odr constant +// CHECK-7: @_ZTI1EIlE = weak_odr constant // F<long> is an implicit template instantiation with no key function, // so its vtable should have weak_odr linkage. -// CHECK: @_ZTV1FIlE = weak_odr constant -// CHECK: @_ZTS1FIlE = weak_odr constant -// CHECK: @_ZTI1FIlE = weak_odr constant +// CHECK-8: @_ZTV1FIlE = weak_odr constant +// CHECK-8: @_ZTS1FIlE = weak_odr constant +// CHECK-8: @_ZTI1FIlE = weak_odr constant // F<int> is an explicit template instantiation declaration without a // key function, so its vtable should have external linkage. -// CHECK: @_ZTV1FIiE = external constant +// CHECK-9: @_ZTV1FIiE = external constant // E<int> is an explicit template instantiation declaration. It has a // key function that is not instantiated, so we should only reference // its vtable, not define it. -// CHECK: @_ZTV1EIiE = external constant +// CHECK-10: @_ZTV1EIiE = external constant // The anonymous struct for e has no linkage, so the vtable should have // internal linkage. -// CHECK: @"_ZTV3$_0" = internal constant -// CHECK: @"_ZTS3$_0" = internal constant -// CHECK: @"_ZTI3$_0" = internal constant +// CHECK-11: @"_ZTV3$_0" = internal constant +// CHECK-11: @"_ZTS3$_0" = internal constant +// CHECK-11: @"_ZTI3$_0" = internal constant // The A vtable should have internal linkage since it is inside an anonymous // namespace. -// CHECK: @_ZTVN12_GLOBAL__N_11AE = internal constant -// CHECK: @_ZTSN12_GLOBAL__N_11AE = internal constant -// CHECK: @_ZTIN12_GLOBAL__N_11AE = internal constant - - +// CHECK-12: @_ZTVN12_GLOBAL__N_11AE = internal constant +// CHECK-12: @_ZTSN12_GLOBAL__N_11AE = internal constant +// CHECK-12: @_ZTIN12_GLOBAL__N_11AE = internal constant + +// RUN: FileCheck --check-prefix=CHECK-G %s < %t +// +// CHECK-G: @_ZTV1GIiE = weak_odr constant +template <typename T> +class G { +public: + G() {} + virtual void f0(); + virtual void f1(); +}; +template <> +void G<int>::f1() {} +template <typename T> +void G<T>::f0() {} +void G_f0() { new G<int>(); } diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp index f8d655145b8f..023b7297c7d7 100644 --- a/test/CodeGenCXX/x86_32-arguments.cpp +++ b/test/CodeGenCXX/x86_32-arguments.cpp @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck %s // Non-trivial dtors, should both be passed indirectly. struct S { ~S(); - int s; + short s; }; // CHECK: define void @_Z1fv(%struct.S* sret % @@ -13,6 +13,7 @@ void f(S) { } // Non-trivial dtors, should both be passed indirectly. class C { +public: ~C(); double c; }; @@ -22,3 +23,94 @@ C g() { return C(); } // CHECK: define void @_Z1f1C(%class.C*) void f(C) { } + + + + +// PR7058 - Missing byval on MI thunk definition. + +// CHECK: define void @_ZThn4_N18BasicAliasAnalysis13getModRefInfoE8CallSite +// ... +// CHECK: %struct.CallSite* byval %CS) +struct CallSite { + unsigned Ptr; + CallSite(unsigned XX) : Ptr(XX) {} +}; + +struct AliasAnalysis { + virtual void xyz(); + virtual void getModRefInfo(CallSite CS) = 0; +}; + +struct ModulePass { + virtual void xx(); +}; + +struct BasicAliasAnalysis : public ModulePass, public AliasAnalysis { + void getModRefInfo(CallSite CS); +}; + +void BasicAliasAnalysis::getModRefInfo(CallSite CS) { +} + +// Check various single element struct type conditions. +// +// PR7098. + +// CHECK: define i64 @_Z2f0v() +struct s0_0 { int x; }; +struct s0_1 : s0_0 { int* y; }; +s0_1 f0() { return s0_1(); } + +// CHECK: define i32 @_Z2f1v() +struct s1_0 { int x; }; +struct s1_1 : s1_0 { }; +s1_1 f1() { return s1_1(); } + +// CHECK: define double @_Z2f2v() +struct s2_0 { double x; }; +struct s2_1 : s2_0 { }; +s2_1 f2() { return s2_1(); } + +// CHECK: define double @_Z2f3v() +struct s3_0 { }; +struct s3_1 { double x; }; +struct s3_2 : s3_0, s3_1 { }; +s3_2 f3() { return s3_2(); } + +// CHECK: define i64 @_Z2f4v() +struct s4_0 { float x; }; +struct s4_1 { float x; }; +struct s4_2 : s4_0, s4_1 { }; +s4_2 f4() { return s4_2(); } + +// CHECK: define i32 @_Z2f5v() +struct s5 { s5(); int &x; }; +s5 f5() { return s5(); } + +// CHECK: define i32 @_Z4f6_0M2s6i(i32 %a) +// CHECK: define i64 @_Z4f6_1M2s6FivE(%{{.*}} byval %a) +// FIXME: It would be nice to avoid byval on the previous case. +struct s6 {}; +typedef int s6::* s6_mdp; +typedef int (s6::*s6_mfp)(); +s6_mdp f6_0(s6_mdp a) { return a; } +s6_mfp f6_1(s6_mfp a) { return a; } + +// CHECK: define double @_Z2f7v() +struct s7_0 { unsigned : 0; }; +struct s7_1 { double x; }; +struct s7 : s7_0, s7_1 { }; +s7 f7() { return s7(); } + +// CHECK: define void @_Z2f8v(%struct.s8* sret %agg.result) +struct s8_0 { }; +struct s8_1 { double x; }; +struct s8 { s8_0 a; s8_1 b; }; +s8 f8() { return s8(); } + +// CHECK: define void @_Z2f9v(%struct.s9* sret %agg.result) +struct s9_0 { unsigned : 0; }; +struct s9_1 { double x; }; +struct s9 { s9_0 a; s9_1 b; }; +s9 f9() { return s9(); } diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp index 7ebbedc9989e..4bc83b85134e 100644 --- a/test/CodeGenCXX/x86_64-arguments.cpp +++ b/test/CodeGenCXX/x86_64-arguments.cpp @@ -25,3 +25,11 @@ void f2(f2_s1 a0) { } struct s3_0 {}; struct s3_1 { struct s3_0 a; long b; }; void f3(struct s3_1 x) {} + +// CHECK: define i64 @_Z4f4_0M2s4i(i64) +// CHECK: define [[i64_i64_ty]] @_Z4f4_1M2s4FivE([[i64_i64_ty]]) +struct s4 {}; +typedef int s4::* s4_mdp; +typedef int (s4::*s4_mfp)(); +s4_mdp f4_0(s4_mdp a) { return a; } +s4_mfp f4_1(s4_mfp a) { return a; } diff --git a/test/CodeGenObjC/atomic-aggregate-property.m b/test/CodeGenObjC/atomic-aggregate-property.m index 2896d379e75a..93eeca820117 100644 --- a/test/CodeGenObjC/atomic-aggregate-property.m +++ b/test/CodeGenObjC/atomic-aggregate-property.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s // rdar: // 7849824 struct s { diff --git a/test/CodeGenObjC/blocks-1.m b/test/CodeGenObjC/blocks-1.m index 76bfd59e41d1..1ac9c30c8a00 100644 --- a/test/CodeGenObjC/blocks-1.m +++ b/test/CodeGenObjC/blocks-1.m @@ -8,6 +8,16 @@ // RUN: grep "_Block_object_assign" %t | count 4 // RUN: grep "objc_read_weak" %t | count 2 // RUN: grep "objc_assign_weak" %t | count 3 +// RUN: %clang_cc1 -x objective-c++ %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 +// RUN: grep "_Block_object_dispose" %t | count 6 +// RUN: grep "__copy_helper_block_" %t | count 4 +// RUN: grep "__destroy_helper_block_" %t | count 4 +// RUN: grep "__Block_byref_id_object_copy_" %t | count 2 +// RUN: grep "__Block_byref_id_object_dispose_" %t | count 2 +// RUN: grep "i32 135)" %t | count 0 +// RUN: grep "_Block_object_assign" %t | count 4 +// RUN: grep "objc_read_weak" %t | count 2 +// RUN: grep "objc_assign_weak" %t | count 3 @interface NSDictionary @end diff --git a/test/CodeGenObjC/blocks-2.m b/test/CodeGenObjC/blocks-2.m index 15160cc52b06..0062e842648b 100644 --- a/test/CodeGenObjC/blocks-2.m +++ b/test/CodeGenObjC/blocks-2.m @@ -1,5 +1,7 @@ // RUN: %clang_cc1 %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 // RUN: grep "objc_assign_strongCast" %t | count 2 +// RUN: %clang_cc1 -x objective-c++ %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 +// RUN: grep "objc_assign_strongCast" %t | count 2 // This should generate a strong cast. diff --git a/test/CodeGenObjC/blocks-ivar-debug.m b/test/CodeGenObjC/blocks-ivar-debug.m new file mode 100644 index 000000000000..d0cf1f10f729 --- /dev/null +++ b/test/CodeGenObjC/blocks-ivar-debug.m @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -g %s -fblocks -S -o %t +// Radar 7959934 + +@interface NSObject { + struct objc_object *isa; +} +@end +@interface Foo : NSObject { + int _prop; +} +@end + +@implementation Foo +- (int)doSomething { + int (^blk)(void) = ^{ return _prop; }; + return blk(); +} + +@end + diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m index 8ba319eefee1..b96a8d942fac 100644 --- a/test/CodeGenObjC/blocks.m +++ b/test/CodeGenObjC/blocks.m @@ -19,7 +19,7 @@ void foo(T *P) { -(void) im0; @end -// RUN: grep 'define internal i32 @"__-\[A im0\]_block_invoke_"' %t +// RUN: grep 'define internal i32 @"__8-\[A im0\]_block_invoke_0"' %t @implementation A -(void) im0 { (void) ^{ return 1; }(); @@ -31,5 +31,11 @@ void foo(T *P) { -(void) im1 { ^(void) { [self im0]; }(); } +-(void) im2 { + ^{ [super im0]; }(); +} +-(void) im3 { + ^{ ^{[super im0];}(); }(); +} @end diff --git a/test/CodeGenObjC/default-property-synthesis.m b/test/CodeGenObjC/default-property-synthesis.m new file mode 100644 index 000000000000..b3eeb22004ae --- /dev/null +++ b/test/CodeGenObjC/default-property-synthesis.m @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi2 -emit-llvm -o %t %s +// rdar://7923851. + +// Superclass declares property. Subclass redeclares the same property. +// Do not @synthesize-by-default in the subclass. P1 +// Superclass declares a property. Subclass declares a different property with the same name +// (such as different type or attributes). Do not @synthesize-by-default in the subclass. P2 +// Superclass conforms to a protocol that declares a property. Subclass redeclares the +// same property. Do not @synthesize-by-default in the subclass. P3 +// Superclass conforms to a protocol that declares a property. Subclass conforms to the +// same protocol or a derived protocol. Do not @synthesize-by-default in the subclass. P4 + + +@protocol PROTO + @property int P3; + @property int P4; +@end + +@protocol PROTO1 <PROTO> + @property int IMP1; +@end + +@interface Super <PROTO> + @property int P1; + @property (copy) id P2; +@end + +@interface Sub : Super <PROTO1> + @property int P1; + @property (nonatomic, retain) id P2; // expected-warning {{property 'P2' 'copy' attribute does not match the property inherited from 'Super'}} \ + // expected-warning {{property 'P2' 'atomic' attribute does not match the property inherited from 'Super'}} + @property int P3; + @property int IMP2; +@end + +@implementation Sub +@end + diff --git a/test/CodeGenObjC/ivar-layout-64-bitfields.m b/test/CodeGenObjC/ivar-layout-64-bitfields.m index 1b6a16b1b8be..9710e16172df 100644 --- a/test/CodeGenObjC/ivar-layout-64-bitfields.m +++ b/test/CodeGenObjC/ivar-layout-64-bitfields.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s @interface I { struct { diff --git a/test/CodeGenObjC/ivar-layout-64.m b/test/CodeGenObjC/ivar-layout-64.m index 60ce1dff57de..f227bfc30d36 100644 --- a/test/CodeGenObjC/ivar-layout-64.m +++ b/test/CodeGenObjC/ivar-layout-64.m @@ -4,6 +4,12 @@ // RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t // RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t // RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\01\\14\\00"' %t +// RUNX: llvm-gcc -ObjC++ -m64 -fobjc-gc -emit-llvm -S -o %t %s && +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o %t %s +// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"A\\00"' %t +// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t +// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t +// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\01\\14\\00"' %t /* diff --git a/test/CodeGenObjC/ivar-layout-no-optimize.m b/test/CodeGenObjC/ivar-layout-no-optimize.m index e7fd1301b810..7760f94a50ab 100644 --- a/test/CodeGenObjC/ivar-layout-no-optimize.m +++ b/test/CodeGenObjC/ivar-layout-no-optimize.m @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s // RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s @interface NSObject { id isa; diff --git a/test/CodeGenObjC/objc-gc-aggr-assign.m b/test/CodeGenObjC/objc-gc-aggr-assign.m new file mode 100644 index 000000000000..9fd64d5645c8 --- /dev/null +++ b/test/CodeGenObjC/objc-gc-aggr-assign.m @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix C %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix CP %s + +static int count; + +typedef struct S { + int ii; +} SS; + +struct type_s { + SS may_recurse; + id id_val; +}; + +@interface NamedObject +{ + struct type_s type_s_ivar; +} +- (void) setSome : (struct type_s) arg; +- (struct type_s) getSome; +@property(assign) struct type_s aggre_prop; +@end + +@implementation NamedObject +- (void) setSome : (struct type_s) arg + { + type_s_ivar = arg; + } +- (struct type_s) getSome + { + return type_s_ivar; + } +@synthesize aggre_prop = type_s_ivar; +@end + +struct type_s some = {{1234}, (id)0}; + +struct type_s get(void) +{ + return some; +} + +void f(const struct type_s *in, struct type_s *out) { + *out = *in; +} + +#ifdef __cplusplus +struct Derived : type_s { }; + +void foo(Derived* src, Derived* dest) { + *dest = *src; +} +#endif + +// CHECK-C: call i8* @objc_memmove_collectable +// CHECK-C: call i8* @objc_memmove_collectable +// CHECK-C: call i8* @objc_memmove_collectable + +// CHECK-CP: call i8* @objc_memmove_collectable +// CHECK-CP: call i8* @objc_memmove_collectable +// CHECK-CP: call i8* @objc_memmove_collectable +// CHECK-CP: call i8* @objc_memmove_collectable diff --git a/test/CodeGenObjC/objc2-new-gc-api-strongcast.m b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m index 1ff2dd3d8de2..0413910855e5 100644 --- a/test/CodeGenObjC/objc2-new-gc-api-strongcast.m +++ b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m @@ -1,9 +1,11 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s // RUN: grep -F '@objc_assign_strongCast' %t | count 4 +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s +// RUN: grep -F '@objc_assign_strongCast' %t | count 4 @interface DSATextSearch @end -DSATextSearch **_uniqueIdToIdentifierArray = ((void *)0); +DSATextSearch **_uniqueIdToIdentifierArray = (0); void foo (int _nextId) { _uniqueIdToIdentifierArray[_nextId] = 0; // objc_assign_strongCast diff --git a/test/CodeGenObjC/objc2-no-write-barrier.m b/test/CodeGenObjC/objc2-no-write-barrier.m index 544c329c5e20..a0ebc100fb2f 100644 --- a/test/CodeGenObjC/objc2-no-write-barrier.m +++ b/test/CodeGenObjC/objc2-no-write-barrier.m @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s // RUN: grep 'objc_assign' %t | count 0 +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: grep 'objc_assign' %t | count 0 typedef struct { int ival; diff --git a/test/CodeGenObjC/objc2-retain-codegen.m b/test/CodeGenObjC/objc2-retain-codegen.m index 2c3317a4854d..9f6620619ecd 100644 --- a/test/CodeGenObjC/objc2-retain-codegen.m +++ b/test/CodeGenObjC/objc2-retain-codegen.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-gc-only -emit-llvm -o %t %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-unknown-unknown -fobjc-gc-only -emit-llvm -o %t %s @interface I0 { I0 *_f0; diff --git a/test/CodeGenObjC/objc2-strong-cast-1.m b/test/CodeGenObjC/objc2-strong-cast-1.m index 509f21a342ae..b79f8a00f7a3 100644 --- a/test/CodeGenObjC/objc2-strong-cast-1.m +++ b/test/CodeGenObjC/objc2-strong-cast-1.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-gc -emit-llvm -o %t %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-unknown-unknown -fobjc-gc -emit-llvm -o %t %s @interface I { __attribute__((objc_gc(strong))) int *i_IdocumentIDs; diff --git a/test/CodeGenObjC/objc2-strong-cast.m b/test/CodeGenObjC/objc2-strong-cast.m index 9ef463c0df10..7291c4e8d2d4 100644 --- a/test/CodeGenObjC/objc2-strong-cast.m +++ b/test/CodeGenObjC/objc2-strong-cast.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fobjc-gc -emit-llvm -o %t %s +// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -emit-llvm -o %t %s @interface I { __attribute__((objc_gc(strong))) signed long *_documentIDs; diff --git a/test/CodeGenObjC/objc2-weak-assign.m b/test/CodeGenObjC/objc2-weak-assign.m index 42fa7738f44e..74c0c00c7caa 100644 --- a/test/CodeGenObjC/objc2-weak-assign.m +++ b/test/CodeGenObjC/objc2-weak-assign.m @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s // RUN: grep -e "objc_assign_weak" %t | grep -e "call" | count 6 +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: grep -e "objc_assign_weak" %t | grep -e "call" | count 6 __weak id* x; id* __weak y; diff --git a/test/CodeGenObjC/objc2-weak-compare.m b/test/CodeGenObjC/objc2-weak-compare.m index cb8ca5ff4c07..8cba1a986094 100644 --- a/test/CodeGenObjC/objc2-weak-compare.m +++ b/test/CodeGenObjC/objc2-weak-compare.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s @interface PBXTarget { @@ -10,6 +11,7 @@ PBXTarget * result; - Meth; @end +extern void foo(); @implementation PBXTarget - Meth { if (_lastKnownTarget != result) diff --git a/test/CodeGenObjC/objc2-weak-ivar-debug.m b/test/CodeGenObjC/objc2-weak-ivar-debug.m index a6fb7fa2751f..8f7acd7619ac 100644 --- a/test/CodeGenObjC/objc2-weak-ivar-debug.m +++ b/test/CodeGenObjC/objc2-weak-ivar-debug.m @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s // RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s +// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s // rdar://7252252 @interface Loop { diff --git a/test/CodeGenObjC/objc2-weak-ivar.m b/test/CodeGenObjC/objc2-weak-ivar.m index cfe1e95952fe..8c91a80b6863 100644 --- a/test/CodeGenObjC/objc2-weak-ivar.m +++ b/test/CodeGenObjC/objc2-weak-ivar.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s @class NSObject; @interface Foo { diff --git a/test/CodeGenObjC/objc2-write-barrier-2.m b/test/CodeGenObjC/objc2-write-barrier-2.m index 9a76c6eb8208..74cd7eafad4f 100644 --- a/test/CodeGenObjC/objc2-write-barrier-2.m +++ b/test/CodeGenObjC/objc2-write-barrier-2.m @@ -2,6 +2,10 @@ // RUN: grep -F '@objc_assign_global' %t | count 7 // RUN: grep -F '@objc_assign_ivar' %t | count 5 // RUN: grep -F '@objc_assign_strongCast' %t | count 8 +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: grep -F '@objc_assign_global' %t | count 7 +// RUN: grep -F '@objc_assign_ivar' %t | count 5 +// RUN: grep -F '@objc_assign_strongCast' %t | count 8 extern id **somefunc(void); extern id *somefunc2(void); diff --git a/test/CodeGenObjC/objc2-write-barrier-3.m b/test/CodeGenObjC/objc2-write-barrier-3.m index 626083b1c42d..cb72cc06e55c 100644 --- a/test/CodeGenObjC/objc2-write-barrier-3.m +++ b/test/CodeGenObjC/objc2-write-barrier-3.m @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s // RUN: grep objc_assign_ivar %t | count 3 // RUN: grep objc_assign_strongCast %t | count 6 +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s +// RUN: grep objc_assign_ivar %t | count 3 +// RUN: grep objc_assign_strongCast %t | count 6 struct Slice { void *__strong * items; diff --git a/test/CodeGenObjC/objc2-write-barrier-4.m b/test/CodeGenObjC/objc2-write-barrier-4.m index 11b4ab4e9604..ab30649bec2b 100644 --- a/test/CodeGenObjC/objc2-write-barrier-4.m +++ b/test/CodeGenObjC/objc2-write-barrier-4.m @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s // RUN: grep objc_assign_global %t | count 3 // RUN: grep objc_assign_strongCast %t | count 2 +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: grep objc_assign_global %t | count 3 +// RUN: grep objc_assign_strongCast %t | count 2 @interface A @end diff --git a/test/CodeGenObjC/objc2-write-barrier-5.m b/test/CodeGenObjC/objc2-write-barrier-5.m index babe26d55a53..373df0cc16b9 100644 --- a/test/CodeGenObjC/objc2-write-barrier-5.m +++ b/test/CodeGenObjC/objc2-write-barrier-5.m @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s // RUN: grep objc_assign_ivar %t | count 0 // RUN: grep objc_assign_strongCast %t | count 5 +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: grep objc_assign_ivar %t | count 0 +// RUN: grep objc_assign_strongCast %t | count 5 @interface TestUnarchiver { diff --git a/test/CodeGenObjC/objc2-write-barrier.m b/test/CodeGenObjC/objc2-write-barrier.m index 0934e0a46ac3..08b65deaa38d 100644 --- a/test/CodeGenObjC/objc2-write-barrier.m +++ b/test/CodeGenObjC/objc2-write-barrier.m @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s // RUN: grep -F '@objc_assign_global' %t | count 21 // RUN: grep -F '@objc_assign_ivar' %t | count 11 +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: grep -F '@objc_assign_global' %t | count 21 +// RUN: grep -F '@objc_assign_ivar' %t | count 11 typedef const struct __CFDictionary * CFDictionaryRef; @@ -49,9 +52,9 @@ struct_with_ids_t GlobalStructArray[10]; // The test cases -void *rhs = 0; +void* rhs = 0; -#define ASSIGNTEST(expr, global) expr = rhs +#define ASSIGNTEST(expr, global) expr = (typeof(expr))rhs int testGlobals() { // Everything in this function generates assign_global intercepts diff --git a/test/CodeGenObjC/property-complex.m b/test/CodeGenObjC/property-complex.m index 59200eba0905..071d0b1d24d2 100644 --- a/test/CodeGenObjC/property-complex.m +++ b/test/CodeGenObjC/property-complex.m @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -S -o - %s -// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -S -o - %s +// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s @interface I0 { @public diff --git a/test/CodeGenObjC/protocols.m b/test/CodeGenObjC/protocols.m index 0f24a1cd1fc1..6dadb11273dc 100644 --- a/test/CodeGenObjC/protocols.m +++ b/test/CodeGenObjC/protocols.m @@ -1,8 +1,9 @@ -// RUN: %clang_cc1 -emit-llvm %s -o %t +// RUN: %clang_cc1 -emit-llvm-only %s void p(const char*, ...); @interface Root ++(int) maxValue; -(int) conformsTo: (id) x; @end @@ -48,3 +49,9 @@ int main() { return 0; } + +// rdar://problem/7992749 +typedef Root<P1> P1Object; +int test10() { + return [P1Object maxValue]; +} diff --git a/test/CodeGenObjCXX/encode.mm b/test/CodeGenObjCXX/encode.mm new file mode 100644 index 000000000000..83fb31e16d58 --- /dev/null +++ b/test/CodeGenObjCXX/encode.mm @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// CHECK: v17@0:8{vector<float, float, float>=}16 +// CHECK: {vector<float, float, float>=} +// CHECK: v24@0:816 + +template <typename T1, typename T2, typename T3> struct vector { + vector(); + vector(T1,T2,T3); +}; + +typedef vector< float, float, float > vector3f; + +@interface SceneNode +{ + vector3f position; +} + +@property (assign, nonatomic) vector3f position; + +@end + +@interface MyOpenGLView +{ +@public + vector3f position; +} +@property vector3f position; +@end + +@implementation MyOpenGLView + +@synthesize position; + +-(void)awakeFromNib { + SceneNode *sn; + vector3f VF3(1.0, 1.0, 1.0); + [sn setPosition:VF3]; +} +@end + + +class Int3 { int x, y, z; }; + +// Enforce @encoding for member pointers. +@interface MemPtr {} +- (void) foo: (int (Int3::*)) member; +@end +@implementation MemPtr +- (void) foo: (int (Int3::*)) member { +} +@end diff --git a/test/CodeGenObjCXX/mangle-blocks.mm b/test/CodeGenObjCXX/mangle-blocks.mm new file mode 100644 index 000000000000..9f57557f8f67 --- /dev/null +++ b/test/CodeGenObjCXX/mangle-blocks.mm @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 %s | FileCheck %s + +// CHECK: @_ZGVN3foo20__foo_block_invoke_05valueE = internal global i64 0 + +int f(); + +void foo() { + // CHECK: define internal i32 @__foo_block_invoke_0 + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN3foo20__foo_block_invoke_05value + (void)^(int x) { + static int value = f(); + return x + value; + }; +} + +// CHECK: define internal i32 @__block_global_0 +int i = ^(int x) { return x;}(i); + +@interface A +- (void)method; +@end + +@implementation A +- (void)method { + // CHECK: define internal signext i8 @"__11-[A method]_block_invoke_0" + (void)^(int x) { + // CHECK: @"_ZN11-[A method]30__11-[A method]_block_invoke_04nameE" + static const char *name = "hello"; + return name[x]; + }; +} +@end + +void foo(int) { + (void)^(int x) { + static const char *name = "hello"; + return name[x]; + }; +} + +namespace N { + // CHECK: define internal signext i8 @__bar_block_invoke_0 + void bar() { + (void)^(int x) { + // CHECK: @_ZN1N3bar20__bar_block_invoke_04nameE + static const char *name = "hello"; + return name[x]; + }; + } +} diff --git a/test/CodeGenObjCXX/property-objects.mm b/test/CodeGenObjCXX/property-objects.mm new file mode 100644 index 000000000000..662dacc55d7d --- /dev/null +++ b/test/CodeGenObjCXX/property-objects.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - | FileCheck %s +// CHECK-NOT: callq _objc_msgSend_stret +// CHECK: call void @_ZN1SC1ERKS_ +// CHECK: call %class.S* @_ZN1SaSERKS_ +// CHECK: call %class.S* @_ZN6CGRectaSERKS_ + +class S { +public: + S& operator = (const S&); + S (const S&); + S (); +}; + +struct CGRect { + CGRect & operator = (const CGRect &); +}; + +@interface I { + S position; + CGRect bounds; +} +@property(assign, nonatomic) S position; +@property CGRect bounds; +@property CGRect frame; +- (void)setFrame:(CGRect)frameRect; +- (CGRect)frame; +- (void) initWithOwner; +@end + +@implementation I +@synthesize position; +@synthesize bounds; +@synthesize frame; +- (void)setFrame:(CGRect)frameRect {} +- (CGRect)frame {return bounds;} + +- (void)initWithOwner { + I* _labelLayer; + CGRect labelLayerFrame = self.bounds; + labelLayerFrame = self.bounds; + _labelLayer.frame = labelLayerFrame; +} +@end + +int main() { + I *i; + S s1; + i.position = s1; + return 0; +} + diff --git a/test/Coverage/ast-printing.cpp b/test/Coverage/ast-printing.cpp index 1a75fb4c6322..0de56422895f 100644 --- a/test/Coverage/ast-printing.cpp +++ b/test/Coverage/ast-printing.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only %s // RUN: %clang_cc1 -ast-print %s // RUN: %clang_cc1 -ast-dump %s -// FIXME: %clang_cc1 -ast-print-xml -o %t %s +// RUN: %clang_cc1 -ast-print-xml -o %t %s // RUN: %clang_cc1 -print-decl-contexts %s // RUN: %clang_cc1 -fdump-record-layouts %s diff --git a/test/Driver/bindings.c b/test/Driver/bindings.c index 2271ab5c6459..e7ec0c597d4b 100644 --- a/test/Driver/bindings.c +++ b/test/Driver/bindings.c @@ -48,7 +48,7 @@ // RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: "bindings.s"' %t // Darwin bindings -// RUN: %clang -ccc-host-triple i386-apple-darwin9 -ccc-print-bindings %s 2> %t +// RUN: %clang -ccc-host-triple i386-apple-darwin9 -no-integrated-as -ccc-print-bindings %s 2> %t // RUN: grep '"clang", inputs: \[".*bindings.c"\], output: ".*\.s"' %t // RUN: grep '"darwin::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t // RUN: grep '"darwin::Link", inputs: \[".*\.o"\], output: "a.out"' %t diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c index f1d67597777a..50bce3b274ca 100644 --- a/test/Driver/clang_f_opts.c +++ b/test/Driver/clang_f_opts.c @@ -1,10 +1,12 @@ -// RUN: %clang -### -S -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s -// RUN: %clang -### -S -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s +// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s +// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-asm -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s // RUN: %clang -### -fshort-enums %s 2>&1 | FileCheck -check-prefix=CHECK-SHORT-ENUMS %s +// CHECK-OPTIONS1: -fgnu-keywords // CHECK-OPTIONS1: -fblocks // CHECK-OPTIONS1: -fpascal-strings +// CHECK_OPTIONS2: -fno-gnu-keywords // CHECK-OPTIONS2: -fmath-errno // CHECK-OPTIONS2: -fno-builtin // CHECK-OPTIONS2: -fshort-wchar diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m index f161bb8d9948..7197bc746d12 100644 --- a/test/FixIt/typo.m +++ b/test/FixIt/typo.m @@ -1,17 +1,18 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// RUN: cp %s %t -// RUN: %clang_cc1 -fsyntax-only -fixit %t || true -// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x objective-c %t -// XFAIL: * +// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -DNON_FIXITS -verify %s +// RUN: %clang -E -P %s -o %t +// RUN: %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fixit %t || true +// RUN: %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -pedantic -Werror %t @interface NSString // expected-note{{'NSString' declared here}} + (int)method:(int)x; @end +#ifdef NON_FIXITS void test() { // FIXME: not providing fix-its NSstring *str = @"A string"; // expected-error{{use of undeclared identifier 'NSstring'; did you mean 'NSString'?}} } +#endif @protocol P1 @optional @@ -80,18 +81,23 @@ void test2(Collide *a) { a->vale = 17; // expected-error{{'Collide' does not have a member named 'vale'; did you mean 'value'?}} } +#ifdef NON_FIXITS @interface Derived : Collid // expected-error{{cannot find interface declaration for 'Collid', superclass of 'Derived'; did you mean 'Collide'?}} @end +#endif +#ifdef NON_FIXITS @protocol NetworkSocket // expected-note{{'NetworkSocket' declared here}} - (int)send:(void*)buffer bytes:(int)bytes; @end @interface IPv6 <Network_Socket> // expected-error{{cannot find protocol declaration for 'Network_Socket'; did you mean 'NetworkSocket'?}} @end +#endif @interface Super -- (int)method; +- (int)method; // expected-note{{using}} +- (int)method2; @end @interface Sub : Super @@ -105,6 +111,18 @@ void test2(Collide *a) { @end +double *isupper(int); + +@interface Sub2 : Super +- (int)method2; +@end + +@implementation Sub2 +- (int)method2 { + return [supper method2]; // expected-error{{unknown receiver 'supper'; did you mean 'super'?}} +} +@end + @interface Ivar @end @@ -112,29 +130,19 @@ void test2(Collide *a) { @property (retain) id ivar; @end +#ifdef NON_FIXITS @interface User <Proto> -- (void)method; +- (void)method; // expected-note{{also found}} @end @implementation User @synthesize ivar; - (void)method { - [ivar method]; // Test that we don't correct 'ivar' to 'Ivar' + // Test that we don't correct 'ivar' to 'Ivar' e + [ivar method]; // expected-warning{{multiple methods named 'method' found}} } @end +#endif -@interface User2 -@end -@interface User2 (Cat) < Proto> -- (void)method; -@end - -@implementation User2 (Cat) -@synthesize ivar; - -- (void)method { - [ivar method]; // Test that we don't correct 'ivar' to 'Ivar' -} -@end diff --git a/test/Index/annotate-tokens-include.c b/test/Index/annotate-tokens-include.c new file mode 100644 index 000000000000..3c3c43b746d6 --- /dev/null +++ b/test/Index/annotate-tokens-include.c @@ -0,0 +1,6 @@ +#include "annotate-tokens-include.h" + +// RUN: c-index-test -test-annotate-tokens=%s:1:1:2:1 %s | FileCheck %s +// CHECK: Identifier: "include" [1:2 - 1:9] preprocessing directive= +// CHECK: Literal: ""annotate-tokens-include.h"" [1:10 - 1:37] preprocessing directive= + diff --git a/test/Index/annotate-tokens-include.h b/test/Index/annotate-tokens-include.h new file mode 100644 index 000000000000..5d5f8f0c9e78 --- /dev/null +++ b/test/Index/annotate-tokens-include.h @@ -0,0 +1 @@ +int foo(); diff --git a/test/Index/annotate-tokens.c b/test/Index/annotate-tokens.c index 7fbf9cc4fb6e..41f182d27148 100644 --- a/test/Index/annotate-tokens.c +++ b/test/Index/annotate-tokens.c @@ -11,55 +11,55 @@ void f(void *ptr) { // RUN: c-index-test -test-annotate-tokens=%s:4:1:9:32 %s | FileCheck %s // CHECK: Identifier: "T" [4:3 - 4:4] TypeRef=T:1:13 -// CHECK: Punctuation: "*" [4:4 - 4:5] +// CHECK: Punctuation: "*" [4:4 - 4:5] VarDecl=t_ptr:4:6 (Definition) // CHECK: Identifier: "t_ptr" [4:6 - 4:11] VarDecl=t_ptr:4:6 (Definition) -// CHECK: Punctuation: "=" [4:12 - 4:13] -// CHECK: Punctuation: "(" [4:14 - 4:15] +// CHECK: Punctuation: "=" [4:12 - 4:13] VarDecl=t_ptr:4:6 (Definition) +// CHECK: Punctuation: "(" [4:14 - 4:15] UnexposedExpr=ptr:3:14 // CHECK: Identifier: "T" [4:15 - 4:16] TypeRef=T:1:13 -// CHECK: Punctuation: "*" [4:17 - 4:18] -// CHECK: Punctuation: ")" [4:18 - 4:19] +// CHECK: Punctuation: "*" [4:17 - 4:18] UnexposedExpr=ptr:3:14 +// CHECK: Punctuation: ")" [4:18 - 4:19] UnexposedExpr=ptr:3:14 // CHECK: Identifier: "ptr" [4:19 - 4:22] DeclRefExpr=ptr:3:14 -// CHECK: Punctuation: ";" [4:22 - 4:23] -// CHECK: Punctuation: "(" [5:3 - 5:4] -// CHECK: Keyword: "void" [5:4 - 5:8] -// CHECK: Punctuation: ")" [5:8 - 5:9] -// CHECK: Keyword: "sizeof" [5:9 - 5:15] -// CHECK: Punctuation: "(" [5:15 - 5:16] +// CHECK: Punctuation: ";" [4:22 - 4:23] UnexposedStmt= +// CHECK: Punctuation: "(" [5:3 - 5:4] UnexposedExpr= +// CHECK: Keyword: "void" [5:4 - 5:8] UnexposedExpr= +// CHECK: Punctuation: ")" [5:8 - 5:9] UnexposedExpr= +// CHECK: Keyword: "sizeof" [5:9 - 5:15] UnexposedExpr= +// CHECK: Punctuation: "(" [5:15 - 5:16] UnexposedExpr= // CHECK: Identifier: "T" [5:16 - 5:17] TypeRef=T:1:13 -// CHECK: Punctuation: ")" [5:17 - 5:18] -// CHECK: Punctuation: ";" [5:18 - 5:19] -// CHECK: Comment: "/* A comment */" [6:3 - 6:18] -// CHECK: Keyword: "struct" [7:3 - 7:9] +// CHECK: Punctuation: ")" [5:17 - 5:18] UnexposedExpr= +// CHECK: Punctuation: ";" [5:18 - 5:19] UnexposedStmt= +// CHECK: Comment: "/* A comment */" [6:3 - 6:18] UnexposedStmt= +// CHECK: Keyword: "struct" [7:3 - 7:9] UnexposedStmt= // CHECK: Identifier: "X" [7:10 - 7:11] TypeRef=struct X:2:8 // CHECK: Identifier: "x" [7:12 - 7:13] VarDecl=x:7:12 (Definition) -// CHECK: Punctuation: "=" [7:14 - 7:15] -// CHECK: Punctuation: "(" [7:16 - 7:17] -// CHECK: Keyword: "struct" [7:17 - 7:23] +// CHECK: Punctuation: "=" [7:14 - 7:15] VarDecl=x:7:12 (Definition) +// CHECK: Punctuation: "(" [7:16 - 7:17] UnexposedExpr= +// CHECK: Keyword: "struct" [7:17 - 7:23] UnexposedExpr= // CHECK: Identifier: "X" [7:24 - 7:25] TypeRef=struct X:2:8 -// CHECK: Punctuation: ")" [7:25 - 7:26] -// CHECK: Punctuation: "{" [7:26 - 7:27] -// CHECK: Literal: "1" [7:27 - 7:28] -// CHECK: Punctuation: "," [7:28 - 7:29] -// CHECK: Literal: "2" [7:30 - 7:31] -// CHECK: Punctuation: "}" [7:31 - 7:32] -// CHECK: Punctuation: ";" [7:32 - 7:33] -// CHECK: Keyword: "void" [8:3 - 8:7] -// CHECK: Punctuation: "*" [8:8 - 8:9] +// CHECK: Punctuation: ")" [7:25 - 7:26] UnexposedExpr= +// CHECK: Punctuation: "{" [7:26 - 7:27] UnexposedExpr= +// CHECK: Literal: "1" [7:27 - 7:28] UnexposedExpr= +// CHECK: Punctuation: "," [7:28 - 7:29] UnexposedExpr= +// CHECK: Literal: "2" [7:30 - 7:31] UnexposedExpr= +// CHECK: Punctuation: "}" [7:31 - 7:32] UnexposedExpr= +// CHECK: Punctuation: ";" [7:32 - 7:33] UnexposedStmt= +// CHECK: Keyword: "void" [8:3 - 8:7] VarDecl=xx:8:9 (Definition) +// CHECK: Punctuation: "*" [8:8 - 8:9] VarDecl=xx:8:9 (Definition) // CHECK: Identifier: "xx" [8:9 - 8:11] VarDecl=xx:8:9 (Definition) -// CHECK: Punctuation: "=" [8:12 - 8:13] +// CHECK: Punctuation: "=" [8:12 - 8:13] VarDecl=xx:8:9 (Definition) // CHECK: Identifier: "ptr" [8:14 - 8:17] DeclRefExpr=ptr:3:14 -// CHECK: Punctuation: "?" [8:18 - 8:19] -// CHECK: Punctuation: ":" [8:20 - 8:21] -// CHECK: Punctuation: "&" [8:22 - 8:23] +// CHECK: Punctuation: "?" [8:18 - 8:19] UnexposedExpr= +// CHECK: Punctuation: ":" [8:20 - 8:21] UnexposedExpr= +// CHECK: Punctuation: "&" [8:22 - 8:23] UnexposedExpr= // CHECK: Identifier: "x" [8:23 - 8:24] DeclRefExpr=x:7:12 -// CHECK: Punctuation: ";" [8:24 - 8:25] -// CHECK: Keyword: "const" [9:3 - 9:8] -// CHECK: Keyword: "char" [9:9 - 9:13] -// CHECK: Punctuation: "*" [9:14 - 9:15] +// CHECK: Punctuation: ";" [8:24 - 8:25] UnexposedStmt= +// CHECK: Keyword: "const" [9:3 - 9:8] UnexposedStmt= +// CHECK: Keyword: "char" [9:9 - 9:13] VarDecl=hello:9:16 (Definition) +// CHECK: Punctuation: "*" [9:14 - 9:15] VarDecl=hello:9:16 (Definition) // CHECK: Identifier: "hello" [9:16 - 9:21] VarDecl=hello:9:16 (Definition) -// CHECK: Punctuation: "=" [9:22 - 9:23] -// CHECK: Literal: ""Hello"" [9:24 - 9:31] -// CHECK: Punctuation: ";" [9:31 - 9:32] -// CHECK: Punctuation: "}" [10:1 - 10:2] +// CHECK: Punctuation: "=" [9:22 - 9:23] VarDecl=hello:9:16 (Definition) +// CHECK: Literal: ""Hello"" [9:24 - 9:31] UnexposedExpr= +// CHECK: Punctuation: ";" [9:31 - 9:32] UnexposedStmt= +// CHECK: Punctuation: "}" [10:1 - 10:2] UnexposedStmt= // RUN: c-index-test -test-annotate-tokens=%s:4:1:165:32 %s | FileCheck %s // RUN: c-index-test -test-annotate-tokens=%s:4:1:165:38 %s | FileCheck %s diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m index ce399d34c6f2..c6e746bcb1b2 100644 --- a/test/Index/annotate-tokens.m +++ b/test/Index/annotate-tokens.m @@ -9,51 +9,245 @@ } @end -// RUN: c-index-test -test-annotate-tokens=%s:1:1:10:5 %s | FileCheck %s -// CHECK: Punctuation: "@" [1:1 - 1:2] -// CHECK: Identifier: "interface" [1:2 - 1:11] +// From <rdar://problem/7971430>, the 'barType' referenced in the ivar +// declarations should be annotated as TypeRefs. +typedef int * barType; +@interface Bar +{ + barType iVar; + barType iVar1, iVar2; +} +@end +@implementation Bar +- (void) method +{ + barType local = iVar; +} +@end + +// From <rdar://problem/7967123>. The ranges for attributes are not +// currently stored, causing most of the tokens to be falsely annotated. +// Since there are no source ranges for attributes, we currently don't +// annotate them. +@interface IBActionTests +- (IBAction) actionMethod:(id)arg; +- (void)foo:(int)x; +@end +extern int ibaction_test(void); +@implementation IBActionTests +- (IBAction) actionMethod:(id)arg +{ + ibaction_test(); + [self foo:0]; +} +- (void) foo:(int)x +{ + (void) x; +} +@end + +// From <rdar://problem/7961995>. Essentially the same issue as 7967123, +// but impacting code marked as IBOutlets. +@interface IBOutletTests +{ + IBOutlet char * anOutlet; +} +- (IBAction) actionMethod:(id)arg; +@property IBOutlet int * aPropOutlet; +@end + +// RUN: c-index-test -test-annotate-tokens=%s:1:1:58:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s +// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12 +// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=Foo:1:12 // CHECK: Identifier: "Foo" [1:12 - 1:15] ObjCInterfaceDecl=Foo:1:12 // CHECK: Punctuation: "-" [2:1 - 2:2] ObjCInstanceMethodDecl=compare::2:1 -// CHECK: Punctuation: "(" [2:3 - 2:4] -// CHECK: Keyword: "int" [2:4 - 2:7] -// CHECK: Punctuation: ")" [2:7 - 2:8] -// CHECK: Identifier: "compare" [2:8 - 2:15] -// CHECK: Punctuation: ":" [2:15 - 2:16] -// CHECK: Punctuation: "(" [2:16 - 2:17] +// CHECK: Punctuation: "(" [2:3 - 2:4] ObjCInstanceMethodDecl=compare::2:1 +// CHECK: Keyword: "int" [2:4 - 2:7] ObjCInstanceMethodDecl=compare::2:1 +// CHECK: Punctuation: ")" [2:7 - 2:8] ObjCInstanceMethodDecl=compare::2:1 +// CHECK: Identifier: "compare" [2:8 - 2:15] ObjCInstanceMethodDecl=compare::2:1 +// CHECK: Punctuation: ":" [2:15 - 2:16] ObjCInstanceMethodDecl=compare::2:1 +// CHECK: Punctuation: "(" [2:16 - 2:17] ObjCInstanceMethodDecl=compare::2:1 // CHECK: Identifier: "Foo" [2:17 - 2:20] ObjCClassRef=Foo:1:12 -// CHECK: Punctuation: "*" [2:20 - 2:21] -// CHECK: Punctuation: ")" [2:21 - 2:22] +// CHECK: Punctuation: "*" [2:20 - 2:21] ParmDecl=other:2:22 (Definition) +// CHECK: Punctuation: ")" [2:21 - 2:22] ParmDecl=other:2:22 (Definition) // CHECK: Identifier: "other" [2:22 - 2:27] ParmDecl=other:2:22 (Definition) -// CHECK: Punctuation: ";" [2:27 - 2:28] -// CHECK: Punctuation: "@" [3:1 - 3:2] -// CHECK: Identifier: "end" [3:2 - 3:5] +// CHECK: Punctuation: ";" [2:27 - 2:28] ObjCInstanceMethodDecl=compare::2:1 +// CHECK: Punctuation: "@" [3:1 - 3:2] ObjCInterfaceDecl=Foo:1:12 +// CHECK: Keyword: "end" [3:2 - 3:5] ObjCInterfaceDecl=Foo:1:12 // CHECK: Punctuation: "@" [5:1 - 5:2] ObjCImplementationDecl=Foo:5:1 (Definition) -// CHECK: Identifier: "implementation" [5:2 - 5:16] -// CHECK: Identifier: "Foo" [5:17 - 5:20] +// CHECK: Keyword: "implementation" [5:2 - 5:16] ObjCImplementationDecl=Foo:5:1 (Definition) +// CHECK: Identifier: "Foo" [5:17 - 5:20] ObjCImplementationDecl=Foo:5:1 (Definition) // CHECK: Punctuation: "-" [6:1 - 6:2] ObjCInstanceMethodDecl=compare::6:1 (Definition) -// CHECK: Punctuation: "(" [6:3 - 6:4] -// CHECK: Keyword: "int" [6:4 - 6:7] -// CHECK: Punctuation: ")" [6:7 - 6:8] -// CHECK: Identifier: "compare" [6:8 - 6:15] -// CHECK: Punctuation: ":" [6:15 - 6:16] -// CHECK: Punctuation: "(" [6:16 - 6:17] +// CHECK: Punctuation: "(" [6:3 - 6:4] ObjCInstanceMethodDecl=compare::6:1 (Definition) +// CHECK: Keyword: "int" [6:4 - 6:7] ObjCInstanceMethodDecl=compare::6:1 (Definition) +// CHECK: Punctuation: ")" [6:7 - 6:8] ObjCInstanceMethodDecl=compare::6:1 (Definition) +// CHECK: Identifier: "compare" [6:8 - 6:15] ObjCInstanceMethodDecl=compare::6:1 (Definition) +// CHECK: Punctuation: ":" [6:15 - 6:16] ObjCInstanceMethodDecl=compare::6:1 (Definition) +// CHECK: Punctuation: "(" [6:16 - 6:17] ObjCInstanceMethodDecl=compare::6:1 (Definition) // CHECK: Identifier: "Foo" [6:17 - 6:20] ObjCClassRef=Foo:1:12 -// CHECK: Punctuation: "*" [6:20 - 6:21] -// CHECK: Punctuation: ")" [6:21 - 6:22] +// CHECK: Punctuation: "*" [6:20 - 6:21] ParmDecl=other:6:22 (Definition) +// CHECK: Punctuation: ")" [6:21 - 6:22] ParmDecl=other:6:22 (Definition) // CHECK: Identifier: "other" [6:22 - 6:27] ParmDecl=other:6:22 (Definition) -// CHECK: Punctuation: "{" [6:28 - 6:29] -// CHECK: Keyword: "return" [7:3 - 7:9] -// CHECK: Literal: "0" [7:10 - 7:11] -// CHECK: Punctuation: ";" [7:11 - 7:12] -// CHECK: Punctuation: "(" [8:3 - 8:4] -// CHECK: Keyword: "void" [8:4 - 8:8] -// CHECK: Punctuation: ")" [8:8 - 8:9] -// CHECK: Punctuation: "@" [8:9 - 8:10] -// CHECK: Identifier: "encode" [8:10 - 8:16] -// CHECK: Punctuation: "(" [8:16 - 8:17] +// CHECK: Punctuation: "{" [6:28 - 6:29] UnexposedStmt= +// CHECK: Keyword: "return" [7:3 - 7:9] UnexposedStmt= +// CHECK: Literal: "0" [7:10 - 7:11] UnexposedExpr= +// CHECK: Punctuation: ";" [7:11 - 7:12] UnexposedStmt= +// CHECK: Punctuation: "(" [8:3 - 8:4] UnexposedExpr= +// CHECK: Keyword: "void" [8:4 - 8:8] UnexposedExpr= +// CHECK: Punctuation: ")" [8:8 - 8:9] UnexposedExpr= +// CHECK: Punctuation: "@" [8:9 - 8:10] UnexposedExpr= +// CHECK: Keyword: "encode" [8:10 - 8:16] UnexposedExpr= +// CHECK: Punctuation: "(" [8:16 - 8:17] UnexposedExpr= // CHECK: Identifier: "Foo" [8:17 - 8:20] ObjCClassRef=Foo:1:12 -// CHECK: Punctuation: ")" [8:20 - 8:21] -// CHECK: Punctuation: ";" [8:21 - 8:22] -// CHECK: Punctuation: "}" [9:1 - 9:2] -// CHECK: Punctuation: "@" [10:1 - 10:2] -// CHECK: Identifier: "end" [10:2 - 10:5] +// CHECK: Punctuation: ")" [8:20 - 8:21] UnexposedExpr= +// CHECK: Punctuation: ";" [8:21 - 8:22] UnexposedStmt= +// CHECK: Punctuation: "}" [9:1 - 9:2] UnexposedStmt= +// CHECK: Punctuation: "@" [10:1 - 10:2] ObjCImplementationDecl=Foo:5:1 (Definition) +// CHECK: Keyword: "end" [10:2 - 10:5] +// CHECK: Keyword: "typedef" [14:1 - 14:8] +// CHECK: Keyword: "int" [14:9 - 14:12] +// CHECK: Punctuation: "*" [14:13 - 14:14] +// CHECK: Identifier: "barType" [14:15 - 14:22] TypedefDecl=barType:14:15 (Definition) +// CHECK: Punctuation: ";" [14:22 - 14:23] +// CHECK: Punctuation: "@" [15:1 - 15:2] ObjCInterfaceDecl=Bar:15:12 +// CHECK: Keyword: "interface" [15:2 - 15:11] ObjCInterfaceDecl=Bar:15:12 +// CHECK: Identifier: "Bar" [15:12 - 15:15] ObjCInterfaceDecl=Bar:15:12 +// CHECK: Punctuation: "{" [16:1 - 16:2] ObjCInterfaceDecl=Bar:15:12 +// CHECK: Identifier: "barType" [17:5 - 17:12] TypeRef=barType:14:15 +// CHECK: Identifier: "iVar" [17:13 - 17:17] ObjCIvarDecl=iVar:17:13 (Definition) +// CHECK: Punctuation: ";" [17:17 - 17:18] ObjCInterfaceDecl=Bar:15:12 +// CHECK: Identifier: "barType" [18:5 - 18:12] TypeRef=barType:14:15 +// CHECK: Identifier: "iVar1" [18:13 - 18:18] ObjCIvarDecl=iVar1:18:13 (Definition) +// CHECK: Punctuation: "," [18:18 - 18:19] ObjCIvarDecl=iVar2:18:20 (Definition) +// CHECK: Identifier: "iVar2" [18:20 - 18:25] ObjCIvarDecl=iVar2:18:20 (Definition) +// CHECK: Punctuation: ";" [18:25 - 18:26] ObjCInterfaceDecl=Bar:15:12 +// CHECK: Punctuation: "}" [19:1 - 19:2] ObjCInterfaceDecl=Bar:15:12 +// CHECK: Punctuation: "@" [20:1 - 20:2] ObjCInterfaceDecl=Bar:15:12 +// CHECK: Keyword: "end" [20:2 - 20:5] ObjCInterfaceDecl=Bar:15:12 +// CHECK: Punctuation: "@" [21:1 - 21:2] ObjCImplementationDecl=Bar:21:1 (Definition) +// CHECK: Keyword: "implementation" [21:2 - 21:16] ObjCImplementationDecl=Bar:21:1 (Definition) +// CHECK: Identifier: "Bar" [21:17 - 21:20] ObjCImplementationDecl=Bar:21:1 (Definition) +// CHECK: Punctuation: "-" [22:1 - 22:2] ObjCInstanceMethodDecl=method:22:1 (Definition) +// CHECK: Punctuation: "(" [22:3 - 22:4] ObjCInstanceMethodDecl=method:22:1 (Definition) +// CHECK: Keyword: "void" [22:4 - 22:8] ObjCInstanceMethodDecl=method:22:1 (Definition) +// CHECK: Punctuation: ")" [22:8 - 22:9] ObjCInstanceMethodDecl=method:22:1 (Definition) +// CHECK: Identifier: "method" [22:10 - 22:16] ObjCInstanceMethodDecl=method:22:1 (Definition) +// CHECK: Punctuation: "{" [23:1 - 23:2] UnexposedStmt= +// CHECK: Identifier: "barType" [24:5 - 24:12] TypeRef=barType:14:15 +// CHECK: Identifier: "local" [24:13 - 24:18] VarDecl=local:24:13 (Definition) +// CHECK: Punctuation: "=" [24:19 - 24:20] VarDecl=local:24:13 (Definition) +// CHECK: Identifier: "iVar" [24:21 - 24:25] MemberRefExpr=iVar:17:13 +// CHECK: Punctuation: ";" [24:25 - 24:26] UnexposedStmt= +// CHECK: Punctuation: "}" [25:1 - 25:2] UnexposedStmt= +// CHECK: Punctuation: "@" [26:1 - 26:2] ObjCImplementationDecl=Bar:21:1 (Definition) +// CHECK: Keyword: "end" [26:2 - 26:5] +// CHECK: Punctuation: "@" [32:1 - 32:2] ObjCInterfaceDecl=IBActionTests:32:12 +// CHECK: Keyword: "interface" [32:2 - 32:11] ObjCInterfaceDecl=IBActionTests:32:12 +// CHECK: Identifier: "IBActionTests" [32:12 - 32:25] ObjCInterfaceDecl=IBActionTests:32:12 +// CHECK: Punctuation: "-" [33:1 - 33:2] ObjCInstanceMethodDecl=actionMethod::33:1 +// CHECK: Punctuation: "(" [33:3 - 33:4] ObjCInstanceMethodDecl=actionMethod::33:1 +// CHECK: Identifier: "IBAction" [33:4 - 33:12] macro instantiation=IBAction +// CHECK: Punctuation: ")" [33:12 - 33:13] ObjCInstanceMethodDecl=actionMethod::33:1 +// CHECK: Identifier: "actionMethod" [33:14 - 33:26] ObjCInstanceMethodDecl=actionMethod::33:1 +// CHECK: Punctuation: ":" [33:26 - 33:27] ObjCInstanceMethodDecl=actionMethod::33:1 +// CHECK: Punctuation: "(" [33:27 - 33:28] ObjCInstanceMethodDecl=actionMethod::33:1 +// CHECK: Identifier: "id" [33:28 - 33:30] TypeRef=id:0:0 +// CHECK: Punctuation: ")" [33:30 - 33:31] ParmDecl=arg:33:31 (Definition) +// CHECK: Identifier: "arg" [33:31 - 33:34] ParmDecl=arg:33:31 (Definition) +// CHECK: Punctuation: ";" [33:34 - 33:35] ObjCInstanceMethodDecl=actionMethod::33:1 +// CHECK: Punctuation: "-" [34:1 - 34:2] ObjCInstanceMethodDecl=foo::34:1 +// CHECK: Punctuation: "(" [34:3 - 34:4] ObjCInstanceMethodDecl=foo::34:1 +// CHECK: Keyword: "void" [34:4 - 34:8] ObjCInstanceMethodDecl=foo::34:1 +// CHECK: Punctuation: ")" [34:8 - 34:9] ObjCInstanceMethodDecl=foo::34:1 +// CHECK: Identifier: "foo" [34:9 - 34:12] ObjCInstanceMethodDecl=foo::34:1 +// CHECK: Punctuation: ":" [34:12 - 34:13] ObjCInstanceMethodDecl=foo::34:1 +// CHECK: Punctuation: "(" [34:13 - 34:14] ObjCInstanceMethodDecl=foo::34:1 +// CHECK: Keyword: "int" [34:14 - 34:17] ParmDecl=x:34:18 (Definition) +// CHECK: Punctuation: ")" [34:17 - 34:18] ParmDecl=x:34:18 (Definition) +// CHECK: Identifier: "x" [34:18 - 34:19] ParmDecl=x:34:18 (Definition) +// CHECK: Punctuation: ";" [34:19 - 34:20] ObjCInstanceMethodDecl=foo::34:1 +// CHECK: Punctuation: "@" [35:1 - 35:2] ObjCInterfaceDecl=IBActionTests:32:12 +// CHECK: Keyword: "end" [35:2 - 35:5] ObjCInterfaceDecl=IBActionTests:32:12 +// CHECK: Keyword: "extern" [36:1 - 36:7] +// CHECK: Keyword: "int" [36:8 - 36:11] FunctionDecl=ibaction_test:36:12 +// CHECK: Identifier: "ibaction_test" [36:12 - 36:25] FunctionDecl=ibaction_test:36:12 +// CHECK: Punctuation: "(" [36:25 - 36:26] FunctionDecl=ibaction_test:36:12 +// CHECK: Keyword: "void" [36:26 - 36:30] FunctionDecl=ibaction_test:36:12 +// CHECK: Punctuation: ")" [36:30 - 36:31] FunctionDecl=ibaction_test:36:12 +// CHECK: Punctuation: ";" [36:31 - 36:32] +// CHECK: Punctuation: "@" [37:1 - 37:2] ObjCImplementationDecl=IBActionTests:37:1 (Definition) +// CHECK: Keyword: "implementation" [37:2 - 37:16] ObjCImplementationDecl=IBActionTests:37:1 (Definition) +// CHECK: Identifier: "IBActionTests" [37:17 - 37:30] ObjCImplementationDecl=IBActionTests:37:1 (Definition) +// CHECK: Punctuation: "-" [38:1 - 38:2] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) +// CHECK: Punctuation: "(" [38:3 - 38:4] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) +// CHECK: Identifier: "IBAction" [38:4 - 38:12] macro instantiation=IBAction +// CHECK: Punctuation: ")" [38:12 - 38:13] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) +// CHECK: Identifier: "actionMethod" [38:14 - 38:26] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) +// CHECK: Punctuation: ":" [38:26 - 38:27] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) +// CHECK: Punctuation: "(" [38:27 - 38:28] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) +// CHECK: Identifier: "id" [38:28 - 38:30] TypeRef=id:0:0 +// CHECK: Punctuation: ")" [38:30 - 38:31] ParmDecl=arg:38:31 (Definition) +// CHECK: Identifier: "arg" [38:31 - 38:34] ParmDecl=arg:38:31 (Definition) +// CHECK: Punctuation: "{" [39:1 - 39:2] UnexposedStmt= +// CHECK: Identifier: "ibaction_test" [40:5 - 40:18] DeclRefExpr=ibaction_test:36:12 +// CHECK: Punctuation: "(" [40:18 - 40:19] CallExpr=ibaction_test:36:12 +// CHECK: Punctuation: ")" [40:19 - 40:20] CallExpr=ibaction_test:36:12 +// CHECK: Punctuation: ";" [40:20 - 40:21] UnexposedStmt= +// CHECK: Punctuation: "[" [41:5 - 41:6] ObjCMessageExpr=foo::34:1 +// CHECK: Identifier: "self" [41:6 - 41:10] DeclRefExpr=self:0:0 +// CHECK: Identifier: "foo" [41:11 - 41:14] ObjCMessageExpr=foo::34:1 +// CHECK: Punctuation: ":" [41:14 - 41:15] ObjCMessageExpr=foo::34:1 +// CHECK: Literal: "0" [41:15 - 41:16] UnexposedExpr= +// CHECK: Punctuation: "]" [41:16 - 41:17] ObjCMessageExpr=foo::34:1 +// CHECK: Punctuation: ";" [41:17 - 41:18] UnexposedStmt= +// CHECK: Punctuation: "}" [42:1 - 42:2] UnexposedStmt= +// CHECK: Punctuation: "-" [43:1 - 43:2] ObjCInstanceMethodDecl=foo::43:1 (Definition) +// CHECK: Punctuation: "(" [43:3 - 43:4] ObjCInstanceMethodDecl=foo::43:1 (Definition) +// CHECK: Keyword: "void" [43:4 - 43:8] ObjCInstanceMethodDecl=foo::43:1 (Definition) +// CHECK: Punctuation: ")" [43:8 - 43:9] ObjCInstanceMethodDecl=foo::43:1 (Definition) +// CHECK: Identifier: "foo" [43:10 - 43:13] ObjCInstanceMethodDecl=foo::43:1 (Definition) +// CHECK: Punctuation: ":" [43:13 - 43:14] ObjCInstanceMethodDecl=foo::43:1 (Definition) +// CHECK: Punctuation: "(" [43:14 - 43:15] ObjCInstanceMethodDecl=foo::43:1 (Definition) +// CHECK: Keyword: "int" [43:15 - 43:18] ParmDecl=x:43:19 (Definition) +// CHECK: Punctuation: ")" [43:18 - 43:19] ParmDecl=x:43:19 (Definition) +// CHECK: Identifier: "x" [43:19 - 43:20] ParmDecl=x:43:19 (Definition) +// CHECK: Punctuation: "{" [44:1 - 44:2] UnexposedStmt= +// CHECK: Punctuation: "(" [45:3 - 45:4] UnexposedExpr=x:43:19 +// CHECK: Keyword: "void" [45:4 - 45:8] UnexposedExpr=x:43:19 +// CHECK: Punctuation: ")" [45:8 - 45:9] UnexposedExpr=x:43:19 +// CHECK: Identifier: "x" [45:10 - 45:11] DeclRefExpr=x:43:19 +// CHECK: Punctuation: ";" [45:11 - 45:12] UnexposedStmt= +// CHECK: Punctuation: "}" [46:1 - 46:2] UnexposedStmt= +// CHECK: Punctuation: "@" [47:1 - 47:2] ObjCImplementationDecl=IBActionTests:37:1 (Definition) +// CHECK: Keyword: "end" [47:2 - 47:5] +// CHECK: Punctuation: "@" [51:1 - 51:2] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Keyword: "interface" [51:2 - 51:11] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Identifier: "IBOutletTests" [51:12 - 51:25] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: "{" [52:1 - 52:2] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Identifier: "IBOutlet" [53:5 - 53:13] macro instantiation=IBOutlet:{{[0-9]+}}:{{[0-9]+}} +// CHECK: Keyword: "char" [53:14 - 53:18] ObjCIvarDecl=anOutlet:53:21 (Definition) +// CHECK: Punctuation: "*" [53:19 - 53:20] ObjCIvarDecl=anOutlet:53:21 (Definition) +// CHECK: Identifier: "anOutlet" [53:21 - 53:29] ObjCIvarDecl=anOutlet:53:21 (Definition) +// CHECK: Punctuation: ";" [53:29 - 53:30] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: "}" [54:1 - 54:2] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: "-" [55:1 - 55:2] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: "(" [55:3 - 55:4] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Identifier: "IBAction" [55:4 - 55:12] macro instantiation=IBAction +// CHECK: Punctuation: ")" [55:12 - 55:13] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Identifier: "actionMethod" [55:14 - 55:26] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: ":" [55:26 - 55:27] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: "(" [55:27 - 55:28] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Identifier: "id" [55:28 - 55:30] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: ")" [55:30 - 55:31] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Identifier: "arg" [55:31 - 55:34] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: ";" [55:34 - 55:35] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: "@" [56:1 - 56:2] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Keyword: "property" [56:2 - 56:10] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Identifier: "IBOutlet" [56:11 - 56:19] macro instantiation=IBOutlet:{{[0-9]+}}:{{[0-9]+}} +// CHECK: Keyword: "int" [56:20 - 56:23] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: "*" [56:24 - 56:25] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Identifier: "aPropOutlet" [56:26 - 56:37] ObjCPropertyDecl=aPropOutlet:56:26 +// CHECK: Punctuation: ";" [56:37 - 56:38] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Punctuation: "@" [57:1 - 57:2] ObjCInterfaceDecl=IBOutletTests:51:12 +// CHECK: Keyword: "end" [57:2 - 57:5] ObjCInterfaceDecl=IBOutletTests:51:12 + diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m index 5b2f86e543b2..22875dbfe851 100644 --- a/test/Index/c-index-api-loadTU-test.m +++ b/test/Index/c-index-api-loadTU-test.m @@ -54,12 +54,24 @@ int main (int argc, const char * argv[]) { main(someEnum, (const char **)bee); } +// Test attribute traversal. +#define IBOutlet __attribute__((iboutlet)) +#define IBOutletCollection(ClassName) __attribute__((iboutletcollection)) +#define IBAction void)__attribute__((ibaction) + +@interface TestAttributes { + IBOutlet char * anOutlet; + IBOutletCollection(id) id anOutletCollection; +} +- (IBAction) actionMethod:(id)arg; +@end + // CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 12:5] // CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:32 - 6:40] -// CHECK: c-index-api-loadTU-test.m:6:32: attribute(iboutlet)= Extent=[6:32 - 6:40] +// CHECK: <invalid loc>:0:0: attribute(iboutlet)= // CHECK: c-index-api-loadTU-test.m:6:29: TypeRef=id:0:0 Extent=[6:29 - 6:31] // CHECK: c-index-api-loadTU-test.m:8:1: ObjCInstanceMethodDecl=myMessage::8:1 Extent=[8:1 - 8:54] -// CHECK: c-index-api-loadTU-test.m:8:1: attribute(ibaction)= Extent=[8:1 - 8:54] +// CHECK: <invalid loc>:0:0: attribute(ibaction)= // CHECK: c-index-api-loadTU-test.m:8:50: ParmDecl=msg:8:50 (Definition) Extent=[8:47 - 8:53] // CHECK: c-index-api-loadTU-test.m:8:47: TypeRef=id:0:0 Extent=[8:47 - 8:49] // CHECK: c-index-api-loadTU-test.m:9:1: ObjCInstanceMethodDecl=foo:9:1 Extent=[9:1 - 9:7] @@ -81,27 +93,29 @@ int main (int argc, const char * argv[]) { // CHECK: c-index-api-loadTU-test.m:33:23: ObjCProtocolRef=SubP:29:1 Extent=[33:23 - 33:27] // CHECK: c-index-api-loadTU-test.m:35:9: ObjCIvarDecl=_anIVar:35:9 (Definition) Extent=[35:9 - 35:16] // CHECK: c-index-api-loadTU-test.m:38:1: ObjCInstanceMethodDecl=bazMethod:38:1 Extent=[38:1 - 38:21] +// CHECK: c-index-api-loadTU-test.m:38:4: ObjCClassRef=Foo:4:12 Extent=[38:4 - 38:7] // CHECK: c-index-api-loadTU-test.m:42:1: EnumDecl=:42:1 (Definition) Extent=[42:1 - 44:2] // CHECK: c-index-api-loadTU-test.m:43:3: EnumConstantDecl=someEnum:43:3 (Definition) Extent=[43:3 - 43:11] // CHECK: c-index-api-loadTU-test.m:46:5: FunctionDecl=main:46:5 (Definition) Extent=[46:5 - 55:2] // CHECK: c-index-api-loadTU-test.m:46:15: ParmDecl=argc:46:15 (Definition) Extent=[46:11 - 46:19] // CHECK: c-index-api-loadTU-test.m:46:34: ParmDecl=argv:46:34 (Definition) Extent=[46:27 - 46:38] -// CHECK: c-index-api-loadTU-test.m:46:5: UnexposedStmt= Extent=[46:42 - 55:2] -// CHECK: c-index-api-loadTU-test.m:46:5: UnexposedStmt= Extent=[47:2 - 47:12] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[46:42 - 55:2] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[47:2 - 47:12] // CHECK: c-index-api-loadTU-test.m:47:8: VarDecl=bee:47:8 (Definition) Extent=[47:2 - 47:11] // CHECK: c-index-api-loadTU-test.m:47:2: ObjCClassRef=Baz:33:12 Extent=[47:2 - 47:5] -// CHECK: c-index-api-loadTU-test.m:47:8: UnexposedStmt= Extent=[48:2 - 48:19] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[48:2 - 48:19] // CHECK: c-index-api-loadTU-test.m:48:5: VarDecl=a:48:5 (Definition) Extent=[48:2 - 48:18] // CHECK: c-index-api-loadTU-test.m:48:2: TypeRef=id:0:0 Extent=[48:2 - 48:4] // CHECK: c-index-api-loadTU-test.m:48:9: ObjCMessageExpr=foo:9:1 Extent=[48:9 - 48:18] // CHECK: c-index-api-loadTU-test.m:48:10: DeclRefExpr=bee:47:8 Extent=[48:10 - 48:13] -// CHECK: c-index-api-loadTU-test.m:48:5: UnexposedStmt= Extent=[49:2 - 49:27] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[49:2 - 49:27] // CHECK: c-index-api-loadTU-test.m:49:12: VarDecl=c:49:12 (Definition) Extent=[49:2 - 49:26] // CHECK: c-index-api-loadTU-test.m:49:2: TypeRef=id:0:0 Extent=[49:2 - 49:4] // CHECK: c-index-api-loadTU-test.m:49:6: ObjCProtocolRef=SubP:29:1 Extent=[49:6 - 49:10] // CHECK: c-index-api-loadTU-test.m:49:16: UnexposedExpr=fooC:10:1 Extent=[49:16 - 49:26] // CHECK: c-index-api-loadTU-test.m:49:16: ObjCMessageExpr=fooC:10:1 Extent=[49:16 - 49:26] -// CHECK: c-index-api-loadTU-test.m:49:12: UnexposedStmt= Extent=[50:2 - 50:15] +// CHECK: c-index-api-loadTU-test.m:49:17: ObjCClassRef=Foo:4:12 Extent=[49:17 - 49:20] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[50:2 - 50:15] // CHECK: c-index-api-loadTU-test.m:50:13: VarDecl=d:50:13 (Definition) Extent=[50:2 - 50:14] // CHECK: c-index-api-loadTU-test.m:50:2: TypeRef=id:0:0 Extent=[50:2 - 50:4] // CHECK: c-index-api-loadTU-test.m:50:6: ObjCProtocolRef=Proto:25:1 Extent=[50:6 - 50:11] @@ -121,4 +135,14 @@ int main (int argc, const char * argv[]) { // CHECK: c-index-api-loadTU-test.m:54:8: DeclRefExpr=someEnum:43:3 Extent=[54:8 - 54:16] // CHECK: c-index-api-loadTU-test.m:54:18: UnexposedExpr=bee:47:8 Extent=[54:18 - 54:36] // CHECK: c-index-api-loadTU-test.m:54:33: DeclRefExpr=bee:47:8 Extent=[54:33 - 54:36] +// CHECK: c-index-api-loadTU-test.m:62:12: ObjCInterfaceDecl=TestAttributes:62:12 Extent=[62:1 - 67:5] +// CHECK: c-index-api-loadTU-test.m:63:19: ObjCIvarDecl=anOutlet:63:19 (Definition) Extent=[63:19 - 63:27] +// CHECK: <invalid loc>:0:0: attribute(iboutlet)= +// CHECK: c-index-api-loadTU-test.m:64:29: ObjCIvarDecl=anOutletCollection:64:29 (Definition) Extent=[64:29 - 64:47] +// CHECK: <invalid loc>:0:0: attribute(iboutletcollection)= +// CHECK: c-index-api-loadTU-test.m:64:26: TypeRef=id:0:0 Extent=[64:26 - 64:28] +// CHECK: c-index-api-loadTU-test.m:66:1: ObjCInstanceMethodDecl=actionMethod::66:1 Extent=[66:1 - 66:35] +// CHECK: <invalid loc>:0:0: attribute(ibaction)= +// CHECK: c-index-api-loadTU-test.m:66:31: ParmDecl=arg:66:31 (Definition) Extent=[66:28 - 66:34] +// CHECK: c-index-api-loadTU-test.m:66:28: TypeRef=id:0:0 Extent=[66:28 - 66:30] diff --git a/test/Index/complete-at-directives.m b/test/Index/complete-at-directives.m index 811bca00efb0..a278ce883666 100644 --- a/test/Index/complete-at-directives.m +++ b/test/Index/complete-at-directives.m @@ -5,25 +5,25 @@ @implementation MyClass @end -// RUN: c-index-test -code-completion-at=%s:2:2 %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: c-index-test -code-completion-at=%s:2:2 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: {TypedText class}{HorizontalSpace }{Placeholder identifier} // CHECK-CC1: {TypedText compatibility_alias}{HorizontalSpace }{Placeholder alias}{HorizontalSpace }{Placeholder class} // CHECK-CC1: {TypedText implementation}{HorizontalSpace }{Placeholder class} // CHECK-CC1: {TypedText interface}{HorizontalSpace }{Placeholder class} // CHECK-CC1: {TypedText protocol}{HorizontalSpace }{Placeholder protocol} -// RUN: c-index-test -code-completion-at=%s:3:2 %s | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: c-index-test -code-completion-at=%s:3:2 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2: {TypedText end} // CHECK-CC2: {TypedText optional} // CHECK-CC2: {TypedText property} // CHECK-CC2: {TypedText required} -// RUN: c-index-test -code-completion-at=%s:6:2 %s | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: c-index-test -code-completion-at=%s:6:2 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: {TypedText dynamic}{HorizontalSpace }{Placeholder property} // CHECK-CC3: {TypedText end} // CHECK-CC3: {TypedText synthesize}{HorizontalSpace }{Placeholder property} -// RUN: c-index-test -code-completion-at=%s:2:1 %s | FileCheck -check-prefix=CHECK-CC4 %s +// RUN: c-index-test -code-completion-at=%s:2:1 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC4 %s // CHECK-CC4: NotImplemented:{TypedText @class}{HorizontalSpace }{Placeholder identifier} // CHECK-CC4: NotImplemented:{TypedText @compatibility_alias}{HorizontalSpace }{Placeholder alias}{HorizontalSpace }{Placeholder class} // CHECK-CC4: NotImplemented:{TypedText @implementation}{HorizontalSpace }{Placeholder class} @@ -34,7 +34,7 @@ // CHECK-CC4: TypedefDecl:{TypedText id} // CHECK-CC4: TypedefDecl:{TypedText SEL} -// RUN: c-index-test -code-completion-at=%s:3:1 %s | FileCheck -check-prefix=CHECK-CC5 %s +// RUN: c-index-test -code-completion-at=%s:3:1 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC5 %s // CHECK-CC5: {TypedText @end} // CHECK-CC5: {TypedText @optional} // CHECK-CC5: {TypedText @property} @@ -45,13 +45,13 @@ // CHECK-CC5: ObjCInterfaceDecl:{TypedText MyClass} // CHECK-CC5: TypedefDecl:{TypedText SEL} -// RUN: c-index-test -code-completion-at=%s:2:23 %s | FileCheck -check-prefix=CHECK-CC6 %s +// RUN: c-index-test -code-completion-at=%s:2:23 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC6 %s // CHECK-CC6: NotImplemented:{TypedText package} // CHECK-CC6: NotImplemented:{TypedText private} // CHECK-CC6: NotImplemented:{TypedText protected} // CHECK-CC6: NotImplemented:{TypedText public} -// RUN: c-index-test -code-completion-at=%s:2:22 %s | FileCheck -check-prefix=CHECK-CC7 %s +// RUN: c-index-test -code-completion-at=%s:2:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC7 %s // CHECK-CC7: NotImplemented:{TypedText @package} // CHECK-CC7: NotImplemented:{TypedText @private} // CHECK-CC7: NotImplemented:{TypedText @protected} diff --git a/test/Index/complete-at-exprstmt.m b/test/Index/complete-at-exprstmt.m index 87e554ff22ae..85370989fd83 100644 --- a/test/Index/complete-at-exprstmt.m +++ b/test/Index/complete-at-exprstmt.m @@ -9,18 +9,18 @@ @synchronized (@encode(MyClass)) { } } @end -// RUN: c-index-test -code-completion-at=%s:9:4 %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: c-index-test -code-completion-at=%s:9:4 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )} // CHECK-CC1: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )} // CHECK-CC1: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )} // CHECK-CC1: {TypedText synchronized}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }} // CHECK-CC1: {TypedText throw}{HorizontalSpace }{Placeholder expression} // CHECK-CC1: {TypedText try}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @catch}{LeftParen (}{Placeholder parameter}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @finally}{LeftBrace {}{Placeholder statements}{RightBrace }} -// RUN: c-index-test -code-completion-at=%s:9:19 %s | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: c-index-test -code-completion-at=%s:9:19 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )} // CHECK-CC2: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )} // CHECK-CC2: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )} -// RUN: c-index-test -code-completion-at=%s:9:3 %s | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: c-index-test -code-completion-at=%s:9:3 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: NotImplemented:{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )} // CHECK-CC3: NotImplemented:{TypedText @protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )} // CHECK-CC3: NotImplemented:{TypedText @selector}{LeftParen (}{Placeholder selector}{RightParen )} diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c index efc82f90a9e6..65af2419213a 100644 --- a/test/Index/complete-exprs.c +++ b/test/Index/complete-exprs.c @@ -7,9 +7,12 @@ int test(int i, int j, int k, int l) { return i | j | k & l; } -// RUN: c-index-test -code-completion-at=%s:7:9 %s | FileCheck -check-prefix=CHECK-CC1 %s -// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} -// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} -// RUN: c-index-test -code-completion-at=%s:7:14 %s | FileCheck -check-prefix=CHECK-CC1 %s -// RUN: c-index-test -code-completion-at=%s:7:18 %s | FileCheck -check-prefix=CHECK-CC1 %s -// RUN: c-index-test -code-completion-at=%s:7:22 %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: macro definition:{TypedText __VERSION__} (70) +// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50) +// CHECK-CC1: NotImplemented:{TypedText float} (40) +// CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (8) +// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30) +// RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: c-index-test -code-completion-at=%s:7:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: c-index-test -code-completion-at=%s:7:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s diff --git a/test/Index/complete-member-access.m b/test/Index/complete-member-access.m index 2502d7705b9c..82efb9511586 100644 --- a/test/Index/complete-member-access.m +++ b/test/Index/complete-member-access.m @@ -26,5 +26,5 @@ void test_props(Int* ptr) { // CHECK-CC1: ObjCPropertyDecl:{ResultType int}{TypedText prop1} // CHECK-CC1: ObjCPropertyDecl:{ResultType float}{TypedText ProtoProp} // RUN: c-index-test -code-completion-at=%s:22:8 %s | FileCheck -check-prefix=CHECK-CC2 %s -// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText IVar} -// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText SuperIVar} +// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText IVar} (20) +// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText SuperIVar} (22) diff --git a/test/Index/complete-recovery.m b/test/Index/complete-recovery.m new file mode 100644 index 000000000000..c28438da66f8 --- /dev/null +++ b/test/Index/complete-recovery.m @@ -0,0 +1,21 @@ +/* Run lines are at the end, since line/column matter in this test. */ + +@interface A +- (void)method:(int)x; +@end + +@implementation A +- (void)method:(int)x { + A *a = [A method:1]; + blarg * blah = wibble +} +@end + +// RUN: c-index-test -code-completion-at=%s:9:20 -Xclang -code-completion-patterns %s 2>%t | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: not grep error %t +// CHECK-CC1: NotImplemented:{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )} +// CHECK-CC1: NotImplemented:{TypedText _Bool} +// CHECK-CC1: VarDecl:{ResultType A *}{TypedText a} +// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} + +// RUN: c-index-test -code-completion-at=%s:10:24 -Xclang -code-completion-patterns %s 2>%t | FileCheck -check-prefix=CHECK-CC1 %s diff --git a/test/Index/load-stmts.cpp b/test/Index/load-stmts.cpp index fdfedfb16efb..cb99aee3ad6d 100644 --- a/test/Index/load-stmts.cpp +++ b/test/Index/load-stmts.cpp @@ -11,8 +11,15 @@ void f(int x) { } // RUN: c-index-test -test-load-source all %s | FileCheck %s -// CHECK: load-stmts.cpp:3:6: UnexposedStmt= Extent=[4:3 - 5:4] -// CHECK: load-stmts.cpp:3:6: UnexposedStmt= Extent=[4:8 - 4:16] +// CHECK: load-stmts.cpp:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:13 - 1:14] +// CHECK: load-stmts.cpp:2:8: StructDecl=X:2:8 (Definition) Extent=[2:1 - 2:23] +// CHECK: load-stmts.cpp:2:16: FieldDecl=a:2:16 (Definition) Extent=[2:16 - 2:17] +// CHECK: load-stmts.cpp:2:19: FieldDecl=b:2:19 (Definition) Extent=[2:19 - 2:20] +// CHECK: load-stmts.cpp:3:6: FunctionDecl=f:3:6 (Definition) Extent=[3:6 - 11:2] +// CHECK: load-stmts.cpp:3:12: ParmDecl=x:3:12 (Definition) Extent=[3:8 - 3:13] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[3:15 - 11:2] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[4:3 - 5:4] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[4:8 - 4:16] // CHECK: load-stmts.cpp:4:10: VarDecl=y:4:10 (Definition) Extent=[4:8 - 4:15] // CHECK: load-stmts.cpp:4:8: TypeRef=T:1:13 Extent=[4:8 - 4:9] // CHECK: load-stmts.cpp:4:14: DeclRefExpr=x:3:12 Extent=[4:14 - 4:15] @@ -23,29 +30,30 @@ void f(int x) { // CHECK: load-stmts.cpp:4:19: DeclRefExpr=z:4:19 Extent=[4:19 - 4:20] // CHECK: load-stmts.cpp:4:26: UnexposedExpr= Extent=[4:26 - 4:29] // CHECK: load-stmts.cpp:4:28: DeclRefExpr=x:3:12 Extent=[4:28 - 4:29] -// CHECK: load-stmts.cpp:4:19: UnexposedStmt= Extent=[4:31 - 5:4] -// CHECK: load-stmts.cpp:4:19: UnexposedStmt= Extent=[6:3 - 6:22] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[4:31 - 5:4] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[6:3 - 6:22] // CHECK: load-stmts.cpp:6:10: VarDecl=z2:6:10 (Definition) Extent=[6:7 - 6:17] // CHECK: load-stmts.cpp:6:7: TypeRef=T:1:13 Extent=[6:7 - 6:8] // CHECK: load-stmts.cpp:6:15: UnexposedExpr= Extent=[6:15 - 6:17] // CHECK: load-stmts.cpp:6:16: DeclRefExpr=x:3:12 Extent=[6:16 - 6:17] // CHECK: load-stmts.cpp:6:10: UnexposedExpr=z2:6:10 Extent=[6:10 - 6:12] // CHECK: load-stmts.cpp:6:10: DeclRefExpr=z2:6:10 Extent=[6:10 - 6:12] -// CHECK: load-stmts.cpp:6:10: UnexposedStmt= Extent=[6:19 - 6:22] -// CHECK: load-stmts.cpp:6:10: UnexposedStmt= Extent=[7:3 - 7:25] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[6:19 - 6:22] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[7:3 - 7:25] // CHECK: load-stmts.cpp:7:13: VarDecl=z3:7:13 (Definition) Extent=[7:10 - 7:20] // CHECK: load-stmts.cpp:7:10: TypeRef=T:1:13 Extent=[7:10 - 7:11] // CHECK: load-stmts.cpp:7:18: UnexposedExpr= Extent=[7:18 - 7:20] // CHECK: load-stmts.cpp:7:19: DeclRefExpr=x:3:12 Extent=[7:19 - 7:20] // CHECK: load-stmts.cpp:7:13: UnexposedExpr=z3:7:13 Extent=[7:13 - 7:15] // CHECK: load-stmts.cpp:7:13: DeclRefExpr=z3:7:13 Extent=[7:13 - 7:15] -// CHECK: load-stmts.cpp:7:13: UnexposedStmt= Extent=[7:22 - 7:25] -// CHECK: load-stmts.cpp:7:13: UnexposedStmt= Extent=[8:3 - 10:4] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[7:22 - 7:25] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[8:3 - 10:4] // CHECK: load-stmts.cpp:8:13: VarDecl=z4:8:13 (Definition) Extent=[8:11 - 8:19] // CHECK: load-stmts.cpp:8:11: TypeRef=T:1:13 Extent=[8:11 - 8:12] // CHECK: load-stmts.cpp:8:18: DeclRefExpr=x:3:12 Extent=[8:18 - 8:19] // CHECK: load-stmts.cpp:8:13: DeclRefExpr=z4:8:13 Extent=[8:13 - 8:15] -// CHECK: load-stmts.cpp:8:13: UnexposedStmt= Extent=[8:21 - 10:4] -// CHECK: load-stmts.cpp:8:13: UnexposedStmt= Extent=[9:3 - 9:17] -// CHECK: load-stmts.cpp:8:13: UnexposedStmt= Extent=[9:12 - 9:17] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[8:21 - 10:4] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[9:3 - 9:17] // CHECK: load-stmts.cpp:9:8: UnexposedExpr= Extent=[9:8 - 9:10] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[9:12 - 9:17] + diff --git a/test/Index/print-typekind.c b/test/Index/print-typekind.c new file mode 100644 index 000000000000..79a9965d4d85 --- /dev/null +++ b/test/Index/print-typekind.c @@ -0,0 +1,20 @@ +typedef int FooType; +int *p; +int *f(int *p, char *x, FooType z) { + FooType w = z; + return p + z; +} + +// RUN: c-index-test -test-print-typekind %s | FileCheck %s +// CHECK: TypedefDecl=FooType:1:13 (Definition) typekind=Typedef [canonical=Int] +// CHECK: VarDecl=p:2:6 typekind=Pointer +// CHECK: FunctionDecl=f:3:6 (Definition) typekind=Unexposed [canonical=Unexposed] +// CHECK: ParmDecl=p:3:13 (Definition) typekind=Pointer +// CHECK: ParmDecl=x:3:22 (Definition) typekind=Pointer +// CHECK: ParmDecl=z:3:33 (Definition) typekind=Typedef [canonical=Int] +// CHECK: VarDecl=w:4:11 (Definition) typekind=Typedef [canonical=Int] +// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] +// CHECK: UnexposedExpr= typekind=Pointer +// CHECK: DeclRefExpr=p:3:13 typekind=Pointer +// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] + diff --git a/test/Index/properties-class-extensions.m b/test/Index/properties-class-extensions.m new file mode 100644 index 000000000000..8bca37e7c9de --- /dev/null +++ b/test/Index/properties-class-extensions.m @@ -0,0 +1,28 @@ +// Test that @properties within class extensions are visited by +// clang_visitChildren only in the class extension, not the original +// @interface (where we have a duplicate declaration - to be removed). +@interface Foo {} @end +@interface Foo (Cat) + @property int a; +@end +@interface Foo () + @property int b; + - (void) bar; +@end + +// RUN: c-index-test -test-load-source local %s | FileCheck %s +// CHECK: properties-class-extensions.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 4:23] +// CHECK: properties-class-extensions.m:5:12: ObjCCategoryDecl=Cat:5:12 Extent=[5:1 - 7:5] +// CHECK: properties-class-extensions.m:5:12: ObjCClassRef=Foo:4:12 Extent=[5:12 - 5:15] +// CHECK: properties-class-extensions.m:6:17: ObjCPropertyDecl=a:6:17 Extent=[6:17 - 6:18] +// CHECK: properties-class-extensions.m:6:17: ObjCInstanceMethodDecl=a:6:17 Extent=[6:17 - 6:18] +// CHECK: properties-class-extensions.m:6:17: ObjCInstanceMethodDecl=setA::6:17 Extent=[6:17 - 6:18] +// CHECK: properties-class-extensions.m:6:17: ParmDecl=a:6:17 (Definition) Extent=[6:17 - 6:18] +// CHECK: properties-class-extensions.m:8:12: ObjCCategoryDecl=:8:12 Extent=[8:1 - 11:5] +// CHECK: properties-class-extensions.m:8:12: ObjCClassRef=Foo:4:12 Extent=[8:12 - 8:15] +// CHECK: properties-class-extensions.m:9:17: ObjCPropertyDecl=b:9:17 Extent=[9:17 - 9:18] +// CHECK: properties-class-extensions.m:9:17: ObjCInstanceMethodDecl=b:9:17 Extent=[9:17 - 9:18] +// CHECK: properties-class-extensions.m:9:17: ObjCInstanceMethodDecl=setB::9:17 Extent=[9:17 - 9:18] +// CHECK: properties-class-extensions.m:9:17: ParmDecl=b:9:17 (Definition) Extent=[9:17 - 9:18] +// CHECK: properties-class-extensions.m:10:3: ObjCInstanceMethodDecl=bar:10:3 Extent=[10:3 - 10:16] + diff --git a/test/Index/remap-load.c b/test/Index/remap-load.c index b8415e6a17d4..d9634a4af676 100644 --- a/test/Index/remap-load.c +++ b/test/Index/remap-load.c @@ -5,8 +5,8 @@ // CHECK: remap-load.c:1:5: FunctionDecl=foo:1:5 (Definition) Extent=[1:5 - 3:2] // CHECK: remap-load.c:1:13: ParmDecl=parm1:1:13 (Definition) Extent=[1:9 - 1:18] // CHECK: remap-load.c:1:26: ParmDecl=parm2:1:26 (Definition) Extent=[1:20 - 1:31] -// CHECK: remap-load.c:1:5: UnexposedStmt= Extent=[1:33 - 3:2] -// CHECK: remap-load.c:1:5: UnexposedStmt= Extent=[2:3 - 2:23] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[1:33 - 3:2] +// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[2:3 - 2:23] // CHECK: remap-load.c:2:10: UnexposedExpr= Extent=[2:10 - 2:23] // CHECK: remap-load.c:2:10: UnexposedExpr= Extent=[2:10 - 2:23] // CHECK: remap-load.c:2:10: UnexposedExpr=parm1:1:13 Extent=[2:10 - 2:15] diff --git a/test/Index/usrs.cpp b/test/Index/usrs.cpp new file mode 100644 index 000000000000..b6a6d3dadab6 --- /dev/null +++ b/test/Index/usrs.cpp @@ -0,0 +1,107 @@ +namespace foo { + int x; + void bar(int z); +} +namespace bar { + typedef int QType; + void bar(QType z); +} + +class ClsA { +public: + int a, b; + ClsA(int A, int B) : a(A), b(B) {} +}; + +namespace foo { + class ClsB : public ClsA { + public: + ClsB() : ClsA(1, 2) {} + int result() const; + }; +} + +int foo::ClsB::result() const { + return a + b; +} + +namespace { + class ClsC : public foo::ClsB {}; + int w; +} + +int z; + +namespace foo { namespace taz { + int x; + static inline int add(int a, int b) { return a + b; } + void sub(int a, int b); +} +} + +namespace foo { namespace taz { + class ClsD : public foo::ClsB { + public: + ClsD& operator=(int x) { a = x; return *this; } + ClsD& operator=(double x) { a = (int) x; return *this; } + ClsD& operator=(const ClsD &x) { a = x.a; return *this; } + static int qux(); + static int uz(int z, ...); + bool operator==(const ClsD &x) const { return a == x.a; } + }; +}} + +extern "C" { + void rez(int a, int b); +} + +// RUN: c-index-test -test-load-source-usrs all %s | FileCheck %s +// CHECK: usrs.cpp c:@N@foo Extent=[1:11 - 4:2] +// CHECK: usrs.cpp c:@N@foo@x Extent=[2:3 - 2:8] +// CHECK: usrs.cpp c:@N@foo@F@bar#I# Extent=[3:8 - 3:18] +// CHECK: usrs.cpp c:usrs.cpp@3:12@N@foo@F@bar#I#@z Extent=[3:12 - 3:17] +// CHECK: usrs.cpp c:@N@bar Extent=[5:11 - 8:2] +// CHECK: usrs.cpp c:usrs.cpp@6:15@N@bar@T@QType Extent=[6:15 - 6:20] +// CHECK: usrs.cpp c:@N@bar@F@bar#I# Extent=[7:8 - 7:20] +// CHECK: usrs.cpp c:usrs.cpp@7:12@N@bar@F@bar#I#@z Extent=[7:12 - 7:19] +// CHECK: usrs.cpp c:@C@ClsA Extent=[10:1 - 14:2] +// CHECK: usrs.cpp c:@C@ClsA@FI@a Extent=[12:7 - 12:8] +// CHECK: usrs.cpp c:@C@ClsA@FI@b Extent=[12:10 - 12:11] +// CHECK: usrs.cpp c:@C@ClsA@F@ClsA#I#I# Extent=[13:3 - 13:37] +// CHECK: usrs.cpp c:usrs.cpp@13:8@C@ClsA@F@ClsA#I#I#@A Extent=[13:8 - 13:13] +// CHECK: usrs.cpp c:usrs.cpp@13:15@C@ClsA@F@ClsA#I#I#@B Extent=[13:15 - 13:20] +// CHECK: usrs.cpp c:@N@foo Extent=[16:11 - 22:2] +// CHECK: usrs.cpp c:@N@foo@C@ClsB Extent=[17:3 - 21:4] +// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@ClsB# Extent=[19:5 - 19:27] +// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[20:9 - 20:17] +// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[24:16 - 26:2] +// CHECK: usrs.cpp c:@aN@C@ClsC Extent=[29:3 - 29:35] +// CHECK: usrs.cpp c:@aN@w Extent=[30:3 - 30:8] +// CHECK: usrs.cpp c:@z Extent=[33:1 - 33:6] +// CHECK: usrs.cpp c:@N@foo Extent=[35:11 - 40:2] +// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[35:27 - 39:2] +// CHECK: usrs.cpp c:@N@foo@N@taz@x Extent=[36:3 - 36:8] +// CHECK: usrs.cpp c:usrs.cpp@37:21@N@foo@N@taz@F@add#I#I# Extent=[37:21 - 37:56] +// CHECK: usrs.cpp c:usrs.cpp@37:25@N@foo@N@taz@F@add#I#I#@a Extent=[37:25 - 37:30] +// CHECK: usrs.cpp c:usrs.cpp@37:32@N@foo@N@taz@F@add#I#I#@b Extent=[37:32 - 37:37] +// CHECK: usrs.cpp c:@N@foo@N@taz@F@sub#I#I# Extent=[38:8 - 38:25] +// CHECK: usrs.cpp c:usrs.cpp@38:12@N@foo@N@taz@F@sub#I#I#@a Extent=[38:12 - 38:17] +// CHECK: usrs.cpp c:usrs.cpp@38:19@N@foo@N@taz@F@sub#I#I#@b Extent=[38:19 - 38:24] +// CHECK: usrs.cpp c:@N@foo Extent=[42:11 - 52:3] +// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[42:27 - 52:2] +// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD Extent=[43:3 - 51:4] +// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#I# Extent=[45:11 - 45:52] +// CHECK: usrs.cpp c:usrs.cpp@45:21@N@foo@N@taz@C@ClsD@F@operator=#I#@x Extent=[45:21 - 45:26] +// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#d# Extent=[46:11 - 46:61] +// CHECK: usrs.cpp c:usrs.cpp@46:21@N@foo@N@taz@C@ClsD@F@operator=#d#@x Extent=[46:21 - 46:29] +// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD# Extent=[47:11 - 47:62] +// CHECK: usrs.cpp c:usrs.cpp@47:27@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD#@x Extent=[47:27 - 47:34] +// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@qux#S Extent=[48:16 - 48:21] +// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@uz#I.#S Extent=[49:16 - 49:30] +// CHECK: usrs.cpp c:usrs.cpp@49:19@N@foo@N@taz@C@ClsD@F@uz#I.#S@z Extent=[49:19 - 49:24] +// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1 Extent=[50:10 - 50:62] +// CHECK: usrs.cpp c:usrs.cpp@50:27@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1@x Extent=[50:27 - 50:34] +// CHECK: usrs.cpp c:@F@rez Extent=[55:8 - 55:25] +// CHECK: usrs.cpp c:usrs.cpp@55:12@F@rez@a Extent=[55:12 - 55:17] +// CHECK: usrs.cpp c:usrs.cpp@55:19@F@rez@b Extent=[55:19 - 55:24] + diff --git a/test/Index/usrs.m b/test/Index/usrs.m index eb0817c27c81..bffd0ee4bbc7 100644 --- a/test/Index/usrs.m +++ b/test/Index/usrs.m @@ -49,18 +49,18 @@ int z; static int local_func(int x) { return x; } // CHECK: usrs.m c:usrs.m@3:19@F@my_helper Extent=[3:19 - 3:60] -// CHECK: usrs.m c:usrs.m@3:29@x Extent=[3:29 - 3:34] -// CHECK: usrs.m c:usrs.m@3:36@y Extent=[3:36 - 3:41] -// CHECK: usrs.m c:@Ea@usrs.m@5:1 Extent=[5:1 - 8:2] -// CHECK: usrs.m c:@Ea@usrs.m@5:1@ABA Extent=[6:3 - 6:6] -// CHECK: usrs.m c:@Ea@usrs.m@5:1@CADABA Extent=[7:3 - 7:9] -// CHECK: usrs.m c:@Ea@usrs.m@10:1 Extent=[10:1 - 13:2] -// CHECK: usrs.m c:@Ea@usrs.m@10:1@FOO Extent=[11:3 - 11:6] -// CHECK: usrs.m c:@Ea@usrs.m@10:1@BAR Extent=[12:3 - 12:6] +// CHECK: usrs.m c:usrs.m@3:29@F@my_helper@x Extent=[3:29 - 3:34] +// CHECK: usrs.m c:usrs.m@3:36@F@my_helper@y Extent=[3:36 - 3:41] +// CHECK: usrs.m c:usrs.m@5:1@Ea Extent=[5:1 - 8:2] +// CHECK: usrs.m c:usrs.m@5:1@Ea@ABA Extent=[6:3 - 6:6] +// CHECK: usrs.m c:usrs.m@5:1@Ea@CADABA Extent=[7:3 - 7:9] +// CHECK: usrs.m c:usrs.m@10:1@Ea Extent=[10:1 - 13:2] +// CHECK: usrs.m c:usrs.m@10:1@Ea@FOO Extent=[11:3 - 11:6] +// CHECK: usrs.m c:usrs.m@10:1@Ea@BAR Extent=[12:3 - 12:6] // CHECK: usrs.m c:@SA@MyStruct Extent=[15:9 - 18:2] // CHECK: usrs.m c:@SA@MyStruct@FI@wa Extent=[16:7 - 16:9] // CHECK: usrs.m c:@SA@MyStruct@FI@moo Extent=[17:7 - 17:10] -// CHECK: usrs.m c:@T@usrs.m@18:3@MyStruct Extent=[18:3 - 18:11] +// CHECK: usrs.m c:usrs.m@18:3@T@MyStruct Extent=[18:3 - 18:11] // CHECK: usrs.m c:@E@Pizza Extent=[20:1 - 23:2] // CHECK: usrs.m c:@E@Pizza@CHEESE Extent=[21:3 - 21:9] // CHECK: usrs.m c:@E@Pizza@MUSHROOMS Extent=[22:3 - 22:12] @@ -72,16 +72,16 @@ static int local_func(int x) { return x; } // CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[30:1 - 30:17] // CHECK: usrs.m c:objc(cs)Foo(im)d1 Extent=[31:15 - 31:17] // CHECK: usrs.m c:objc(cs)Foo(im)setD1: Extent=[31:15 - 31:17] -// CHECK: usrs.m c:usrs.m@31:15@d1 Extent=[31:15 - 31:17] +// CHECK: usrs.m c:usrs.m@31:15objc(cs)Foo(im)setD1:@d1 Extent=[31:15 - 31:17] // CHECK: usrs.m c:objc(cs)Foo Extent=[34:1 - 45:2] // CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[35:1 - 39:2] -// CHECK: usrs.m c:usrs.m@36:10@a Extent=[36:10 - 36:19] -// CHECK: usrs.m c:@z Extent=[37:10 - 37:15] +// CHECK: usrs.m c:usrs.m@36:10objc(cs)Foo(im)godzilla@a Extent=[36:10 - 36:19] +// CHECK: usrs.m c:objc(cs)Foo(im)godzilla@z Extent=[37:10 - 37:15] // CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[40:1 - 43:2] -// CHECK: usrs.m c:usrs.m@41:3@local_var Extent=[41:3 - 41:16] +// CHECK: usrs.m c:usrs.m@41:3objc(cs)Foo(cm)kingkong@local_var Extent=[41:3 - 41:16] // CHECK: usrs.m c:objc(cs)Foo@d1 Extent=[44:13 - 44:15] // CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15] // CHECK: usrs.m c:@z Extent=[47:1 - 47:6] // CHECK: usrs.m c:usrs.m@49:12@F@local_func Extent=[49:12 - 49:43] -// CHECK: usrs.m c:usrs.m@49:23@x Extent=[49:23 - 49:28] +// CHECK: usrs.m c:usrs.m@49:23@F@local_func@x Extent=[49:23 - 49:28] diff --git a/test/Lexer/gnu_keywords.c b/test/Lexer/gnu_keywords.c index 3234f58114a6..c4bd9b3e59d6 100644 --- a/test/Lexer/gnu_keywords.c +++ b/test/Lexer/gnu_keywords.c @@ -1,7 +1,7 @@ -// RUN: %clang -DGNU_KEYWORDS -std=gnu89 -fsyntax-only -verify %s -// RUN: %clang -DGNU_KEYWORDS -std=c99 -fgnu-keywords -fsyntax-only -verify %s -// RUN: %clang -std=c99 -fsyntax-only -verify %s -// RUN: %clang -std=gnu89 -fno-gnu-keywords -fsyntax-only -verify %s +// RUN: %clang_cc1 -DGNU_KEYWORDS -std=gnu89 -fsyntax-only -verify %s +// RUN: %clang_cc1 -DGNU_KEYWORDS -std=c99 -fgnu-keywords -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=gnu89 -fno-gnu-keywords -fsyntax-only -verify %s void f() { #ifdef GNU_KEYWORDS diff --git a/test/Lexer/hexfloat.cpp b/test/Lexer/hexfloat.cpp index 5a62556ff616..a3b230e78f16 100644 --- a/test/Lexer/hexfloat.cpp +++ b/test/Lexer/hexfloat.cpp @@ -1,5 +1,5 @@ -//RUN: %clang_cc1 -fsyntax-only -verify -//RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify +// RUN: %clang_cc1 -fsyntax-only -verify -pedantic +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify #ifndef __GXX_EXPERIMENTAL_CXX0X__ float f = 0x1p+1; // expected-warning {{incompatible with C++0x}} diff --git a/test/Makefile b/test/Makefile index e9d89454b898..c3b3eab58945 100644 --- a/test/Makefile +++ b/test/Makefile @@ -18,7 +18,7 @@ ifndef TESTARGS ifdef VERBOSE TESTARGS = -v else -TESTARGS = -s -v +TESTARGS = -s -v endif endif diff --git a/test/Misc/diag-aka-types.cpp b/test/Misc/diag-aka-types.cpp new file mode 100644 index 000000000000..7233c4e85b49 --- /dev/null +++ b/test/Misc/diag-aka-types.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify + +struct X {}; +typedef X foo_t; + +foo_t *ptr; +char c1 = ptr; // expected-error{{'foo_t *' (aka 'X *')}} + +const foo_t &ref = foo_t(); +char c2 = ref; // expected-error{{'foo_t const' (aka 'X const')}} diff --git a/test/PCH/Inputs/namespaces.h b/test/PCH/Inputs/namespaces.h index 1bab7463fbbb..553aadd1f9ed 100644 --- a/test/PCH/Inputs/namespaces.h +++ b/test/PCH/Inputs/namespaces.h @@ -6,8 +6,35 @@ namespace N1 { namespace N1 { typedef int t2; + + void used_func(); + + struct used_cls { }; } namespace N2 { typedef float t1; + + namespace Inner { + typedef int t3; + }; +} + +namespace { + void anon() { } + class C; +} + +namespace N3 { + namespace { + class C; + } +} + +namespace Alias1 = N2::Inner; + +using namespace N2::Inner; + +extern "C" { + void ext(); } diff --git a/test/PCH/cxx_exprs.cpp b/test/PCH/cxx_exprs.cpp index 0f0fe88dc54a..ec7041b9843a 100644 --- a/test/PCH/cxx_exprs.cpp +++ b/test/PCH/cxx_exprs.cpp @@ -33,3 +33,7 @@ static_assert(!false_value, "false_value is false"); // CXXNullPtrLiteralExpr cxx_null_ptr_result null_ptr = nullptr; + +// CXXTypeidExpr +typeid_result1 typeid_1 = 0; +typeid_result2 typeid_2 = 0;
\ No newline at end of file diff --git a/test/PCH/cxx_exprs.h b/test/PCH/cxx_exprs.h index a871aa201f12..f64792238991 100644 --- a/test/PCH/cxx_exprs.h +++ b/test/PCH/cxx_exprs.h @@ -1,11 +1,12 @@ // Header for PCH test cxx_exprs.cpp + // CXXStaticCastExpr typedef __typeof__(static_cast<void *>(0)) static_cast_result; // CXXDynamicCastExpr -struct Base { virtual void f(); }; -struct Derived : Base { }; +struct Base { Base(int); virtual void f(int x = 492); ~Base(); }; +struct Derived : Base { Derived(); void g(); }; Base *base_ptr; typedef __typeof__(dynamic_cast<Derived *>(base_ptr)) dynamic_cast_result; @@ -27,3 +28,56 @@ const bool false_value = false; // CXXNullPtrLiteralExpr typedef __typeof__(nullptr) cxx_null_ptr_result; + +void foo(Derived *P) { + // CXXMemberCallExpr + P->f(12); +} + + +// FIXME: This is a hack until <typeinfo> works completely. +namespace std { + class type_info {}; +} + +// CXXTypeidExpr - Both expr and type forms. +typedef __typeof__(typeid(int))* typeid_result1; +typedef __typeof__(typeid(2))* typeid_result2; + +Derived foo(); + +Derived::Derived() : Base(4) { +} + +void Derived::g() { + // CXXThisExpr + f(2); // Implicit + this->f(1); // Explicit + + // CXXThrowExpr + throw; + throw 42; + + // CXXDefaultArgExpr + f(); + + const Derived &X = foo(); + + // FIXME: How do I make a CXXBindReferenceExpr, CXXConstructExpr? + + int A = int(0.5); // CXXFunctionalCastExpr + A = int(); // CXXZeroInitValueExpr + + new Base(4); // CXXNewExpr + +} + + +// FIXME: The comment on CXXTemporaryObjectExpr is broken, this doesn't make +// one. +struct CtorStruct { CtorStruct(int, float); }; + +CtorStruct create_CtorStruct() { + return CtorStruct(1, 3.14f); // CXXTemporaryObjectExpr +}; + diff --git a/test/PCH/namespaces.cpp b/test/PCH/namespaces.cpp index eef9e06e5462..532d627fadcf 100644 --- a/test/PCH/namespaces.cpp +++ b/test/PCH/namespaces.cpp @@ -8,7 +8,36 @@ int int_val; N1::t1 *ip1 = &int_val; N1::t2 *ip2 = &int_val; +N2::Inner::t3 *ip3 = &int_val; float float_val; namespace N2 { } N2::t1 *fp1 = &float_val; + +Alias1::t3 *ip4 = &int_val; +t3 *ip5 = &int_val; + +void(*funp1)() = anon; + +namespace { + class C; +} +C* cp1; + +namespace N3 { + namespace { + class C; + } +} + +N3::C *cp2; + +void(*funp2)() = ext; + +using N1::used_func; +void (*pused)() = used_func; + +// FIXME: Disabled until CXXRecord serialization is re-added. +// using N1::used_cls; +// used_cls s1; +// used_cls* ps1 = &s1; diff --git a/test/Parser/cxx-undeclared-identifier.cpp b/test/Parser/cxx-undeclared-identifier.cpp new file mode 100644 index 000000000000..36d8f7a65381 --- /dev/null +++ b/test/Parser/cxx-undeclared-identifier.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s + +class Foo::Bar { // expected-error {{use of undeclared identifier 'Foo'}} \ + // expected-note {{to match this '{'}} \ + // expected-error {{expected ';' after class}} + // expected-error {{expected '}'}} diff --git a/test/Parser/namespaces.cpp b/test/Parser/namespaces.cpp new file mode 100644 index 000000000000..b8c7819a019f --- /dev/null +++ b/test/Parser/namespaces.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// PR6596 +namespace g { enum { o = 0 }; } + +void foo() { + namespace a { typedef g::o o; } // expected-error{{namespaces can only be defined in global or namespace scope}} +} diff --git a/test/Parser/pragma-options.c b/test/Parser/pragma-options.c new file mode 100644 index 000000000000..332249fdcfe3 --- /dev/null +++ b/test/Parser/pragma-options.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s + +/* expected-warning {{expected 'align' following '#pragma options'}} */ #pragma options +/* expected-warning {{expected '=' following '#pragma options align'}} */ #pragma options align +/* expected-warning {{expected identifier in '#pragma options'}} */ #pragma options align = +/* expected-warning {{invalid alignment option in '#pragma options align'}} */ #pragma options align = foo +/* expected-warning {{extra tokens at end of '#pragma options'}} */ #pragma options align = reset foo + +#pragma options align=natural +#pragma options align=reset +#pragma options align=mac68k +/* expected-warning {{unsupported alignment option}} */ #pragma options align=power diff --git a/test/Parser/recovery.c b/test/Parser/recovery.c index 8e7181e0ba05..6cd95da878d2 100644 --- a/test/Parser/recovery.c +++ b/test/Parser/recovery.c @@ -73,3 +73,8 @@ void foo() { int X; X = 4 // expected-error{{expected ';' after expression}} } + + +// rdar://7980651 +typedef int intptr_t; // expected-note {{'intptr_t' declared here}} +void bar(intptr y); // expected-error {{unknown type name 'intptr'; did you mean 'intptr_t'?}} diff --git a/test/Parser/switch-recovery.cpp b/test/Parser/switch-recovery.cpp new file mode 100644 index 000000000000..8eb4cff4fbe1 --- /dev/null +++ b/test/Parser/switch-recovery.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// <rdar://problem/7971948> +struct A {}; +struct B { + void foo() { + switch (a) { // expected-error{{use of undeclared identifier 'a'}} + default: + return; + } + } +}; diff --git a/test/Rewriter/rewrite-block-argument.m b/test/Rewriter/rewrite-block-argument.m new file mode 100644 index 000000000000..4ebbef9abcbd --- /dev/null +++ b/test/Rewriter/rewrite-block-argument.m @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o %t %t-rw.cpp +// radar 7987817 + +void *sel_registerName(const char *); + +@interface Test { +} +@end + +@implementation Test + +- (void)enumerateProvidersWithBlock:(void (^)(void))block { + block(); +} + +- (void)providerEnumerator { + ^(void (^providerBlock)(void)) { + [self enumerateProvidersWithBlock:providerBlock]; + }; +} + +- (void)testNilBlock { + [self enumerateProvidersWithBlock:0]; +} + +@end + + + +int main(int argc, char *argv[]) { + return 0; +} diff --git a/test/Rewriter/rewrite-local-static-id.mm b/test/Rewriter/rewrite-local-static-id.mm new file mode 100644 index 000000000000..a0b85f4f4dfd --- /dev/null +++ b/test/Rewriter/rewrite-local-static-id.mm @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o %t %t-rw.cpp +// radar 7946975 + +void *sel_registerName(const char *); + +@interface foo +@end + +@interface foo2 : foo ++ (id)x; +@end + +typedef void (^b_t)(void); + +void bar(b_t block); + +void f() { + static id foo = 0; + bar(^{ + foo = [foo2 x]; + }); +} + diff --git a/test/Rewriter/rewrite-no-nextline.mm b/test/Rewriter/rewrite-no-nextline.mm new file mode 100644 index 000000000000..0c3657c90678 --- /dev/null +++ b/test/Rewriter/rewrite-no-nextline.mm @@ -0,0 +1,10 @@ +// 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 7946975 + +@interface RootObject { +} +@end void doStuff(); +int main(int argc, char *argv[]) { + return 0; +} diff --git a/test/Sema/attr-sentinel.c b/test/Sema/attr-sentinel.c index db90d078b3f7..5ca6a8d00113 100644 --- a/test/Sema/attr-sentinel.c +++ b/test/Sema/attr-sentinel.c @@ -4,7 +4,7 @@ #define ATTR __attribute__ ((__sentinel__)) -void foo1 (int x, ...) ATTR; // expected-note {{function has been explicitly marked sentinel here}} +void foo1 (int x, ...) ATTR; // expected-note 2 {{function has been explicitly marked sentinel here}} void foo5 (int x, ...) __attribute__ ((__sentinel__(1))); // expected-note {{function has been explicitly marked sentinel here}} void foo6 (int x, ...) __attribute__ ((__sentinel__(5))); // expected-note {{function has been explicitly marked sentinel here}} void foo7 (int x, ...) __attribute__ ((__sentinel__(0))); // expected-note {{function has been explicitly marked sentinel here}} @@ -24,6 +24,12 @@ void test1() { foo7(1, NULL); // OK foo12(1); // expected-warning {{not enough variable arguments in 'foo12' declaration to fit a sentinel}} + + // PR 5685 + struct A {}; + struct A a, b, c; + foo1(3, &a, &b, &c); // expected-warning {{missing sentinel in function call}} + foo1(3, &a, &b, &c, (struct A*) 0); } diff --git a/test/Sema/c89.c b/test/Sema/c89.c index 8a9e622d8749..038f7e537d76 100644 --- a/test/Sema/c89.c +++ b/test/Sema/c89.c @@ -61,7 +61,7 @@ void foo(T); /* typedef for void is allowed */ void foo(void) {} /* PR2759 */ -void test10 (int x[*]); /* expected-warning {{use of C99-specific array features}} */ +void test10 (int x[*]); /* expected-warning {{variable length arrays are a C99 feature, accepted as an extension}} */ void test11 (int x[static 4]); /* expected-warning {{use of C99-specific array features}} */ void test12 (int x[const 4]) { /* expected-warning {{use of C99-specific array features}} */ diff --git a/test/Sema/compare.c b/test/Sema/compare.c index 631b69420293..f997dc1a73bf 100644 --- a/test/Sema/compare.c +++ b/test/Sema/compare.c @@ -23,8 +23,8 @@ int ints(long a, unsigned long b) { ((signed char) a == b) + // expected-warning {{comparison of integers of different signs}} ((long) a == (unsigned long) b) + // expected-warning {{comparison of integers of different signs}} ((int) a == (unsigned int) b) + // expected-warning {{comparison of integers of different signs}} - ((short) a == (unsigned short) b) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a == (unsigned char) b) + // expected-warning {{comparison of integers of different signs}} + ((short) a == (unsigned short) b) + + ((signed char) a == (unsigned char) b) + (a < (unsigned long) b) + // expected-warning {{comparison of integers of different signs}} (a < (unsigned int) b) + (a < (unsigned short) b) + @@ -35,8 +35,8 @@ int ints(long a, unsigned long b) { ((signed char) a < b) + // expected-warning {{comparison of integers of different signs}} ((long) a < (unsigned long) b) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) b) + // expected-warning {{comparison of integers of different signs}} - ((short) a < (unsigned short) b) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < (unsigned char) b) + // expected-warning {{comparison of integers of different signs}} + ((short) a < (unsigned short) b) + + ((signed char) a < (unsigned char) b) + // (A,b) (A == (unsigned long) b) + @@ -87,8 +87,8 @@ int ints(long a, unsigned long b) { ((signed char) a < B) + ((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}} - ((short) a < (unsigned short) B) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < (unsigned char) B) + // expected-warning {{comparison of integers of different signs}} + ((short) a < (unsigned short) B) + + ((signed char) a < (unsigned char) B) + // (C,b) (C == (unsigned long) b) + @@ -139,8 +139,8 @@ int ints(long a, unsigned long b) { ((signed char) a < C) + ((long) a < (unsigned long) C) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) C) + // expected-warning {{comparison of integers of different signs}} - ((short) a < (unsigned short) C) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < (unsigned char) C) + // expected-warning {{comparison of integers of different signs}} + ((short) a < (unsigned short) C) + + ((signed char) a < (unsigned char) C) + // (0x80000,b) (0x80000 == (unsigned long) b) + @@ -191,8 +191,8 @@ int ints(long a, unsigned long b) { ((signed char) a < 0x80000) + ((long) a < (unsigned long) 0x80000) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) 0x80000) + // expected-warning {{comparison of integers of different signs}} - ((short) a < (unsigned short) 0x80000) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < (unsigned char) 0x80000) + // expected-warning {{comparison of integers of different signs}} + ((short) a < (unsigned short) 0x80000) + + ((signed char) a < (unsigned char) 0x80000) + // We should be able to avoid warning about this. (b != (a < 4 ? 1 : 2)) + diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c index 5e2c1a46248a..6e248bc3cfec 100644 --- a/test/Sema/conditional-expr.c +++ b/test/Sema/conditional-expr.c @@ -52,7 +52,9 @@ void foo() { enum Enum { EVal }; test0 = test0 ? EVal : test0; test0 = test0 ? EVal : (int) test0; // okay: EVal is an int - test0 = test0 ? (unsigned) EVal : (int) test0; // expected-warning {{operands of ? are integers of different signs}} + test0 = test0 ? // expected-warning {{operands of ? are integers of different signs}} + (unsigned) EVal + : (int) test0; } int Postgresql() { @@ -68,3 +70,8 @@ int f0(int a) { // GCC considers this a warning. return a ? f1() : nil; // expected-warning {{pointer/integer type mismatch in conditional expression ('int' and 'void *')}} expected-warning {{incompatible pointer to integer conversion returning 'void *' from a function with result type 'int'}} } + +int f2(int x) { + // We can suppress this because the immediate context wants an int. + return (x != 0) ? 0U : x; +} diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c index addedd91f7e8..5b09ec6d9708 100644 --- a/test/Sema/conversion.c +++ b/test/Sema/conversion.c @@ -287,3 +287,13 @@ void test_7676608(void) { char c = 5; f7676608(c *= q); } + +// <rdar://problem/7904686> +void test_7904686(void) { + const int i = -1; + unsigned u1 = i; // expected-warning {{implicit cast changes signedness}} + u1 = i; // expected-warning {{implicit cast changes signedness}} + + unsigned u2 = -1; // expected-warning {{implicit cast changes signedness}} + u2 = -1; // expected-warning {{implicit cast changes signedness}} +} diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index bdc2bb0c9abe..d6d37961d922 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -251,3 +251,6 @@ void test_pr_6697() { myprintf_PR_6697("%1$s\n", 1, (int) 0); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}} } +void rdar8026030(FILE *fp) { + fprintf(fp, "\%"); // expected-warning{{incomplete format specifier}} +} diff --git a/test/Sema/init.c b/test/Sema/init.c index b9867cf5027b..c2c29ad9b04b 100644 --- a/test/Sema/init.c +++ b/test/Sema/init.c @@ -131,3 +131,17 @@ const wchar_t widestr[] = L"asdf"; // PR5447 const double pr5447 = (0.05 < -1.0) ? -1.0 : 0.0499878; +// PR4386 + +// None of these are constant initializers, but we implement GCC's old +// behaviour of accepting bar and zed but not foo. GCC's behaviour was +// changed in 2007 (rev 122551), so we should be able to change too one +// day. +int PR4386_bar(); +int PR4386_foo() __attribute((weak)); +int PR4386_zed(); + +int PR4386_a = ((void *) PR4386_bar) != 0; +int PR4386_b = ((void *) PR4386_foo) != 0; // expected-error{{initializer element is not a compile-time constant}} +int PR4386_c = ((void *) PR4386_zed) != 0; +int PR4386_zed() __attribute((weak)); diff --git a/test/Sema/pragma-align-mac68k-unsupported.c b/test/Sema/pragma-align-mac68k-unsupported.c new file mode 100644 index 000000000000..6588aa17a15e --- /dev/null +++ b/test/Sema/pragma-align-mac68k-unsupported.c @@ -0,0 +1,4 @@ +// RUN: %clang-cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s +// RUN: %clang-cc1 -triple i386-pc-linux-gnu -fsyntax-only -verify %s + +/* expected-error {{mac68k alignment pragma is not supported}} */ #pragma options align=mac68k diff --git a/test/Sema/pragma-align-mac68k.c b/test/Sema/pragma-align-mac68k.c new file mode 100644 index 000000000000..d13a0bebb767 --- /dev/null +++ b/test/Sema/pragma-align-mac68k.c @@ -0,0 +1,98 @@ +// RUN: %clang-cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s + +#include <stddef.h> + +#pragma options align=mac68k + +typedef float __attribute__((vector_size (8))) v2f_t; +typedef float __attribute__((vector_size (16))) v4f_t; + +extern int a0_0[__alignof(v2f_t) == 8 ? 1 : -1]; +extern int a0_1[__alignof(v4f_t) == 16 ? 1 : -1]; + +struct s1 { + char f0; + int f1; +}; +extern int a1_0[offsetof(struct s1, f0) == 0 ? 1 : -1]; +extern int a1_1[offsetof(struct s1, f1) == 2 ? 1 : -1]; +extern int a1_2[sizeof(struct s1) == 6 ? 1 : -1]; +extern int a1_3[__alignof(struct s1) == 2 ? 1 : -1]; + +struct s2 { + char f0; + double f1; +}; +extern int a2_0[offsetof(struct s2, f0) == 0 ? 1 : -1]; +extern int a2_1[offsetof(struct s2, f1) == 2 ? 1 : -1]; +extern int a2_2[sizeof(struct s2) == 10 ? 1 : -1]; +extern int a2_3[__alignof(struct s2) == 2 ? 1 : -1]; + +struct s3 { + char f0; + v4f_t f1; +}; +extern int a3_0[offsetof(struct s3, f0) == 0 ? 1 : -1]; +extern int a3_1[offsetof(struct s3, f1) == 2 ? 1 : -1]; +extern int a3_2[sizeof(struct s3) == 18 ? 1 : -1]; +extern int a3_3[__alignof(struct s3) == 2 ? 1 : -1]; + +struct s4 { + char f0; + char f1; +}; +extern int a4_0[offsetof(struct s4, f0) == 0 ? 1 : -1]; +extern int a4_1[offsetof(struct s4, f1) == 1 ? 1 : -1]; +extern int a4_2[sizeof(struct s4) == 2 ? 1 : -1]; +extern int a4_3[__alignof(struct s4) == 2 ? 1 : -1]; + +struct s5 { + unsigned f0 : 9; + unsigned f1 : 9; +}; +extern int a5_0[sizeof(struct s5) == 4 ? 1 : -1]; +extern int a5_1[__alignof(struct s5) == 2 ? 1 : -1]; + +struct s6 { + unsigned : 0; + unsigned : 0; +}; +extern int a6_0[sizeof(struct s6) == 0 ? 1 : -1]; +extern int a6_1[__alignof(struct s6) == 2 ? 1 : -1]; + +struct s7 { + char : 1; + unsigned : 1; +}; +extern int a7_0[sizeof(struct s7) == 2 ? 1 : -1]; +extern int a7_1[__alignof(struct s7) == 2 ? 1 : -1]; + +struct s8 { + char f0; + unsigned : 1; +}; +extern int a8_0[sizeof(struct s8) == 2 ? 1 : -1]; +extern int a8_1[__alignof(struct s8) == 2 ? 1 : -1]; + +struct s9 { + char f0[3]; + unsigned : 0; + char f1; +}; +extern int a9_0[sizeof(struct s9) == 6 ? 1 : -1]; +extern int a9_1[__alignof(struct s9) == 2 ? 1 : -1]; + +struct s10 { + char f0; +}; +extern int a10_0[sizeof(struct s10) == 2 ? 1 : -1]; +extern int a10_1[__alignof(struct s10) == 2 ? 1 : -1]; + +struct s11 { + char f0; + v2f_t f1; +}; +extern int a11_0[offsetof(struct s11, f0) == 0 ? 1 : -1]; +extern int a11_1[offsetof(struct s11, f1) == 2 ? 1 : -1]; +extern int a11_2[sizeof(struct s11) == 10 ? 1 : -1]; +extern int a11_3[__alignof(struct s11) == 2 ? 1 : -1]; diff --git a/test/Sema/pragma-pack-and-options-align.c b/test/Sema/pragma-pack-and-options-align.c new file mode 100644 index 000000000000..c880ed6305b4 --- /dev/null +++ b/test/Sema/pragma-pack-and-options-align.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -triple i686-apple-darwin9 %s -fsyntax-only -verify + +// Check that #pragma pack and #pragma options share the same stack. + +#pragma pack(push, 1) +struct s0 { + char c; + int x; +}; +extern int a[sizeof(struct s0) == 5 ? 1 : -1]; + +#pragma options align=natural +struct s1 { + char c; + int x; +}; +extern int a[sizeof(struct s1) == 8 ? 1 : -1]; + +#pragma pack(pop) +struct s2 { + char c; + int x; +}; +extern int a[sizeof(struct s2) == 5 ? 1 : -1]; +#pragma pack(pop) + +struct s3 { + char c; + int x; +}; +extern int a[sizeof(struct s3) == 8 ? 1 : -1]; + +/* expected-warning {{#pragma options align=reset failed: stack empty}} */ #pragma options align=reset +/* expected-warning {{#pragma pack(pop, ...) failed: stack empty}} */ #pragma pack(pop) diff --git a/test/Sema/scope-check.c b/test/Sema/scope-check.c index 6f8640255a9e..f3881ed086ac 100644 --- a/test/Sema/scope-check.c +++ b/test/Sema/scope-check.c @@ -19,7 +19,7 @@ void test3clean(int*); int test3() { goto L; // expected-error{{illegal goto into protected scope}} -int a __attribute((cleanup(test3clean))); // expected-note {{jump bypasses initialization of declaration with __attribute__((cleanup))}} +int a __attribute((cleanup(test3clean))); // expected-note {{jump bypasses initialization of variable with __attribute__((cleanup))}} L: return a; } @@ -133,20 +133,20 @@ int test8(int x) { void test9(int n, void *P) { int Y; int Z = 4; - goto *P; // ok. + goto *P; // expected-warning {{indirect goto might cross protected scopes}} L2: ; - int a[n]; // expected-note 2 {{jump bypasses initialization of variable length array}} + int a[n]; // expected-note {{jump bypasses initialization of variable length array}} -L3: +L3: // expected-note {{possible target of indirect goto}} L4: - goto *P; // expected-warning {{illegal indirect goto in protected scope, unknown effect on scopes}} + goto *P; goto L3; // ok goto L4; // ok void *Ptrs[] = { - &&L2, // Ok. - &&L3 // expected-warning {{address taken of label in protected scope, jump to it would have unknown effect on scope}} + &&L2, + &&L3 }; } @@ -193,3 +193,9 @@ void test12(int n) { }; } +void test13(int n, void *p) { + int vla[n]; + goto *p; + a0: ; + static void *ps[] = { &&a0 }; +} diff --git a/test/Sema/switch.c b/test/Sema/switch.c index e63a1942bba5..27ad06657e26 100644 --- a/test/Sema/switch.c +++ b/test/Sema/switch.c @@ -24,36 +24,37 @@ void foo(int X) { void test3(void) { // empty switch; - switch (0); + switch (0); // expected-warning {{no case matching constant switch condition '0'}} } extern int g(); void test4() { - switch (1) { + int cond; + switch (cond) { case 0 && g(): case 1 || g(): break; } - switch(1) { + switch(cond) { case g(): // expected-error {{expression is not an integer constant expression}} case 0 ... g(): // expected-error {{expression is not an integer constant expression}} break; } - switch (1) { + switch (cond) { case 0 && g() ... 1 || g(): break; } - switch (1) { + switch (cond) { case g() && 0: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}} break; } - switch (1) { + switch (cond) { case 0 ... g() || 1: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}} break; } @@ -68,7 +69,7 @@ void test5(int z) { } void test6() { - const char ch = 'a'; + char ch = 'a'; switch(ch) { case 1234: // expected-warning {{overflow converting case value}} break; @@ -261,3 +262,18 @@ void f1(unsigned x) { default: break; } } + +void test15() { + int i = 0; + switch (1) { // expected-warning {{no case matching constant switch condition '1'}} + case 0: i = 0; break; + case 2: i++; break; + } +} + +void test16() { + const char c = '5'; + switch (c) { // expected-warning {{no case matching constant switch condition '53'}} + case '6': return; + } +} diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c index 4ae0d4b46504..15608ec8a4be 100644 --- a/test/Sema/unused-expr.c +++ b/test/Sema/unused-expr.c @@ -110,3 +110,11 @@ void *some_function(void); void t10() { (void*) some_function(); //expected-warning {{expression result unused; should this cast be to 'void'?}} } + +void f(int i, ...) { + __builtin_va_list ap; + + __builtin_va_start(ap, i); + __builtin_va_arg(ap, int); + __builtin_va_end(ap); +} diff --git a/test/SemaCXX/alignof-sizeof-reference.cpp b/test/SemaCXX/alignof-sizeof-reference.cpp index f02282d72d30..dd64d6a23ae3 100644 --- a/test/SemaCXX/alignof-sizeof-reference.cpp +++ b/test/SemaCXX/alignof-sizeof-reference.cpp @@ -7,3 +7,9 @@ void test() { static_assert(alignof(r) == 1, "bad alignment"); static_assert(sizeof(r) == 1, "bad size"); } + +void f(); +void f(int); +void g() { + sizeof(&f); // expected-error{{invalid application of 'sizeof' to an overloaded function}} +} diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp index 5c34e016e57d..5f84bcca28db 100644 --- a/test/SemaCXX/anonymous-union.cpp +++ b/test/SemaCXX/anonymous-union.cpp @@ -121,3 +121,37 @@ typedef struct _s { int Foo; }; } s, *ps; + +// <rdar://problem/7987650> +namespace test4 { + class A { + struct { + int s0; // expected-note {{declared private here}} + double s1; // expected-note {{declared private here}} + union { + int su0; // expected-note {{declared private here}} + double su1; // expected-note {{declared private here}} + }; + }; + union { + int u0; // expected-note {{declared private here}} + double u1; // expected-note {{declared private here}} + struct { + int us0; // expected-note {{declared private here}} + double us1; // expected-note {{declared private here}} + }; + }; + }; + + void test() { + A a; + (void) a.s0; // expected-error {{private member}} + (void) a.s1; // expected-error {{private member}} + (void) a.su0; // expected-error {{private member}} + (void) a.su1; // expected-error {{private member}} + (void) a.u0; // expected-error {{private member}} + (void) a.u1; // expected-error {{private member}} + (void) a.us0; // expected-error {{private member}} + (void) a.us1; // expected-error {{private member}} + } +} diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp index d5662d3f6313..2164f9dd17f2 100644 --- a/test/SemaCXX/attr-deprecated.cpp +++ b/test/SemaCXX/attr-deprecated.cpp @@ -64,3 +64,129 @@ void D::f() { } void f(D* d) { d->f(); } + + +// Overloaded namespace members. +namespace test1 { + void foo(int) __attribute__((deprecated)); + void test1() { foo(10); } // expected-warning {{deprecated}} + void foo(short) __attribute__((deprecated)); + void test2(short s) { foo(s); } // expected-warning {{deprecated}} + void foo(long); + void test3(long l) { foo(l); } + struct A { + friend void foo(A*) __attribute__((deprecated)); + }; + void test4(A *a) { foo(a); } // expected-warning {{deprecated}} + + namespace ns { + struct Foo {}; + void foo(const Foo &f) __attribute__((deprecated)); + } + void test5() { + foo(ns::Foo()); // expected-warning {{deprecated}} + } +} + +// Overloaded class members. +namespace test2 { + struct A { + void foo(int) __attribute__((deprecated)); + void foo(long); + static void bar(int) __attribute__((deprecated)); + static void bar(long); + + void test2(int i, long l); + }; + void test1(int i, long l) { + A a; + a.foo(i); // expected-warning {{deprecated}} + a.foo(l); + a.bar(i); // expected-warning {{deprecated}} + a.bar(l); + A::bar(i); // expected-warning {{deprecated}} + A::bar(l); + } + + void A::test2(int i, long l) { + foo(i); // expected-warning {{deprecated}} + foo(l); + bar(i); // expected-warning {{deprecated}} + bar(l); + } +} + +// Overloaded operators. +namespace test3 { + struct A { + void operator*(const A &); + void operator*(int) __attribute__((deprecated)); + void operator-(const A &) const; + }; + void operator+(const A &, const A &); + void operator+(const A &, int) __attribute__((deprecated)); + void operator-(const A &, int) __attribute__((deprecated)); + + void test() { + A a, b; + a + b; + a + 1; // expected-warning {{deprecated}} + a - b; + a - 1; // expected-warning {{deprecated}} + a * b; + a * 1; // expected-warning {{deprecated}} + } +} + +// Overloaded operator call. +namespace test4 { + struct A { + typedef void (*intfn)(int); + typedef void (*unintfn)(unsigned); + operator intfn() __attribute__((deprecated)); + operator unintfn(); + void operator ()(A &) __attribute__((deprecated)); + void operator ()(const A &); + }; + + void test() { + A a; + a(1); // expected-warning {{deprecated}} + a(1U); + + A &b = a; + const A &c = a; + a(b); // expected-warning {{deprecated}} + a(c); + } +} + +namespace test5 { + struct A { + operator int() __attribute__((deprecated)); + operator long(); + }; + void test1(A a) { + int i = a; // expected-warning {{deprecated}} + long l = a; + } + + void foo(int); + void foo(void*); + void bar(long); + void bar(void*); + void test2(A a) { + foo(a); // expected-warning {{deprecated}} + bar(a); + } + + struct B { + int myInt; + long myLong; + + B(A &a) : + myInt(a), // expected-warning {{deprecated}} + myLong(a) + {} + }; +} diff --git a/test/SemaCXX/blocks.cpp b/test/SemaCXX/blocks.cpp index 94295437e161..baa79e7d8971 100644 --- a/test/SemaCXX/blocks.cpp +++ b/test/SemaCXX/blocks.cpp @@ -9,3 +9,35 @@ void tovoid_test(int (^f)(int, int)) { void reference_lvalue_test(int& (^f)()) { f() = 10; } + +// PR 7165 +namespace test1 { + void g(void (^)()); + struct Foo { + void foo(); + void test() { + (void) ^{ foo(); }; + } + }; +} + +namespace test2 { + int repeat(int value, int (^block)(int), unsigned n) { + while (n--) value = block(value); + return value; + } + + class Power { + int base; + + public: + Power(int base) : base(base) {} + int calculate(unsigned n) { + return repeat(1, ^(int v) { return v * base; }, n); + } + }; + + int test() { + return Power(2).calculate(10); + } +} diff --git a/test/SemaCXX/c99-variable-length-array.cpp b/test/SemaCXX/c99-variable-length-array.cpp new file mode 100644 index 000000000000..7dc912a0d5f6 --- /dev/null +++ b/test/SemaCXX/c99-variable-length-array.cpp @@ -0,0 +1,116 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wvla %s +struct NonPOD { + NonPOD(); +}; + +struct NonPOD2 { + NonPOD np; +}; + +struct POD { + int x; + int y; +}; + +// We allow VLAs of POD types, only. +void vla(int N) { + int array1[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} + POD array2[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} + NonPOD array3[N]; // expected-error{{variable length array of non-POD element type 'NonPOD'}} + NonPOD2 array4[N][3]; // expected-error{{variable length array of non-POD element type 'NonPOD2'}} +} + +/// Warn about VLAs in templates. +template<typename T> +void vla_in_template(int N, T t) { + int array1[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} +} + +struct HasConstantValue { + static const unsigned int value = 2; +}; + +struct HasNonConstantValue { + static unsigned int value; +}; + +template<typename T> +void vla_in_template(T t) { + int array2[T::value]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} +} + +template void vla_in_template<HasConstantValue>(HasConstantValue); +template void vla_in_template<HasNonConstantValue>(HasNonConstantValue); // expected-note{{instantiation of}} + +template<typename T> struct X0 { }; + +// Cannot use any variably-modified type with a template parameter or +// argument. +void inst_with_vla(int N) { + int array[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} + X0<__typeof__(array)> x0a; // expected-error{{variably modified type 'typeof (array)' (aka 'int [N]') cannot be used as a template argument}} +} + +template<typename T> +struct X1 { + template<int (&Array)[T::value]> // expected-error{{non-type template parameter of variably modified type 'int (&)[HasNonConstantValue::value]'}} \ + // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} + struct Inner { + + }; +}; + +X1<HasConstantValue> x1a; +X1<HasNonConstantValue> x1b; // expected-note{{in instantiation of}} + +// Template argument deduction does not allow deducing a size from a VLA. +template<typename T, unsigned N> +void accept_array(T (&array)[N]); // expected-note{{candidate template ignored: failed template argument deduction}} + +void test_accept_array(int N) { + int array[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} + accept_array(array); // expected-error{{no matching function for call to 'accept_array'}} +} + +// Variably-modified types cannot be used in local classes. +void local_classes(int N) { + struct X { + int size; + int array[N]; // expected-error{{fields must have a constant size: 'variable length array in structure' extension will never be supported}} \ + // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} + }; +} + +namespace PR7206 { + void f(int x) { + struct edge_info { + float left; + float right; + }; + struct edge_info edgeInfo[x]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} + } +} + +namespace rdar8020206 { + template<typename T> + void f(int i) { + const unsigned value = i; + int array[value * i]; // expected-warning 2{{variable length arrays are a C99 feature, accepted as an extension}} + } + + template void f<int>(int); // expected-note{{instantiation of}} +} + +namespace rdar8021385 { + typedef int my_int; + struct A { typedef int my_int; }; + template<typename T> + struct B { + typedef typename T::my_int my_int; + void f0() { + int M = 4; + my_int a[M]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}} + } + }; + B<A> a; +} diff --git a/test/SemaCXX/c99.cpp b/test/SemaCXX/c99.cpp index f4c3639e16a9..b0bd45dea3d1 100644 --- a/test/SemaCXX/c99.cpp +++ b/test/SemaCXX/c99.cpp @@ -1,8 +1,3 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s - -void f0(int i) { - char array[i]; // expected-error{{variable length arrays}} -} - void f1(int i[static 5]) { // expected-error{{C99}} } diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp index 7eea67ad4455..b5cecbcf937b 100644 --- a/test/SemaCXX/class.cpp +++ b/test/SemaCXX/class.cpp @@ -136,3 +136,26 @@ namespace pr6629 { }; }; } + +namespace PR7153 { + class EnclosingClass { + public: + struct A { } mutable *member; + }; + + void f(const EnclosingClass &ec) { + ec.member = 0; + } +} + +namespace PR7196 { + struct A { + int a; + + void f() { + char i[sizeof(a)]; + enum { x = sizeof(i) }; + enum { y = sizeof(a) }; + } + }; +} diff --git a/test/SemaCXX/compare.cpp b/test/SemaCXX/compare.cpp index cd243e3d6b23..4790347220d6 100644 --- a/test/SemaCXX/compare.cpp +++ b/test/SemaCXX/compare.cpp @@ -19,8 +19,8 @@ int test0(long a, unsigned long b) { ((signed char) a == b) + // expected-warning {{comparison of integers of different signs}} ((long) a == (unsigned long) b) + // expected-warning {{comparison of integers of different signs}} ((int) a == (unsigned int) b) + // expected-warning {{comparison of integers of different signs}} - ((short) a == (unsigned short) b) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a == (unsigned char) b) + // expected-warning {{comparison of integers of different signs}} + ((short) a == (unsigned short) b) + + ((signed char) a == (unsigned char) b) + (a < (unsigned long) b) + // expected-warning {{comparison of integers of different signs}} (a < (unsigned int) b) + (a < (unsigned short) b) + @@ -31,8 +31,8 @@ int test0(long a, unsigned long b) { ((signed char) a < b) + // expected-warning {{comparison of integers of different signs}} ((long) a < (unsigned long) b) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) b) + // expected-warning {{comparison of integers of different signs}} - ((short) a < (unsigned short) b) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < (unsigned char) b) + // expected-warning {{comparison of integers of different signs}} + ((short) a < (unsigned short) b) + + ((signed char) a < (unsigned char) b) + // (A,b) (A == (unsigned long) b) + @@ -83,8 +83,8 @@ int test0(long a, unsigned long b) { ((signed char) a < B) + ((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}} - ((short) a < (unsigned short) B) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < (unsigned char) B) + // expected-warning {{comparison of integers of different signs}} + ((short) a < (unsigned short) B) + + ((signed char) a < (unsigned char) B) + // (C,b) (C == (unsigned long) b) + @@ -135,8 +135,8 @@ int test0(long a, unsigned long b) { ((signed char) a < C) + ((long) a < (unsigned long) C) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) C) + // expected-warning {{comparison of integers of different signs}} - ((short) a < (unsigned short) C) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < (unsigned char) C) + // expected-warning {{comparison of integers of different signs}} + ((short) a < (unsigned short) C) + + ((signed char) a < (unsigned char) C) + // (0x80000,b) (0x80000 == (unsigned long) b) + @@ -187,8 +187,8 @@ int test0(long a, unsigned long b) { ((signed char) a < 0x80000) + ((long) a < (unsigned long) 0x80000) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) 0x80000) + // expected-warning {{comparison of integers of different signs}} - ((short) a < (unsigned short) 0x80000) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < (unsigned char) 0x80000) + // expected-warning {{comparison of integers of different signs}} + ((short) a < (unsigned short) 0x80000) + + ((signed char) a < (unsigned char) 0x80000) + 10 ; diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp index a812a5920d65..a09ff2bd417d 100644 --- a/test/SemaCXX/conditional-expr.cpp +++ b/test/SemaCXX/conditional-expr.cpp @@ -238,3 +238,40 @@ namespace PR6757 { (void)(true ? Bar() : Foo3()); // expected-error{{no viable constructor copying temporary}} } } + +// Reduced from selfhost. +namespace test1 { + struct A { + enum Foo { + fa, fb, fc, fd, fe, ff + }; + + Foo x(); + }; + + void foo(int); + + void test(A *a) { + foo(a ? a->x() : 0); + } +} + +namespace rdar7998817 { + class X { + X(X&); // expected-note{{declared private here}} + + struct ref { }; + + public: + X(); + X(ref); + + operator ref(); + }; + + void f(bool B) { + X x; + (void)(B? x // expected-error{{calling a private constructor of class 'rdar7998817::X'}} + : X()); + } +} diff --git a/test/SemaCXX/constant-expression.cpp b/test/SemaCXX/constant-expression.cpp index a17dd58dab03..1341036d83da 100644 --- a/test/SemaCXX/constant-expression.cpp +++ b/test/SemaCXX/constant-expression.cpp @@ -57,8 +57,8 @@ template <int itval, Enum etval> struct C { i10 = sizeof(Struct), i11 = true? 1 + cval * Struct::sval ^ itval / (int)1.5 - sizeof(Struct) : 0 ; - void f() { - switch(0) { + void f(int cond) { + switch(cond) { case 0 + 1: case 100 + eval: case 200 + cval: diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp index dee6d131e4ad..668c60036662 100644 --- a/test/SemaCXX/default-assignment-operator.cpp +++ b/test/SemaCXX/default-assignment-operator.cpp @@ -1,15 +1,14 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s class Base { // expected-error {{cannot define the implicit default assignment operator for 'Base', because non-static reference member 'ref' can't use default assignment operator}} \ - // expected-warning{{class 'Base' does not declare any constructor to initialize its non-modifiable members}} \ - // expected-note {{synthesized method is first required here}} + // expected-warning{{class 'Base' does not declare any constructor to initialize its non-modifiable members}} int &ref; // expected-note {{declared here}} \ // expected-note{{reference member 'ref' will never be initialized}} }; class X : Base { // // expected-error {{cannot define the implicit default assignment operator for 'X', because non-static const member 'cint' can't use default assignment operator}} \ - // expected-note {{synthesized method is first required here}} -public: +// expected-note{{assignment operator for 'Base' first required here}} +public: X(); const int cint; // expected-note {{declared here}} }; @@ -29,7 +28,7 @@ Z z2; // Test1 void f(X x, const X cx) { - x = cx; + x = cx; // expected-note{{assignment operator for 'X' first required here}} x = cx; z1 = z2; } @@ -74,8 +73,7 @@ void i() { // Test5 -class E1 { // expected-error{{cannot define the implicit default assignment operator for 'E1', because non-static const member 'a' can't use default assignment operator}} \ - // expected-note {{synthesized method is first required here}} +class E1 { // expected-error{{cannot define the implicit default assignment operator for 'E1', because non-static const member 'a' can't use default assignment operator}} public: const int a; // expected-note{{declared here}} @@ -86,7 +84,7 @@ public: E1 e1, e2; void j() { - e1 = e2; + e1 = e2; // expected-note{{assignment operator for 'E1' first required here}} } namespace ProtectedCheck { @@ -103,7 +101,8 @@ namespace ProtectedCheck { X x; }; - void f(Z z) { z = z; } // + void f(Z z) { z = z; } // expected-note{{implicit default copy assignment operator}} + } namespace MultiplePaths { diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp index c3dc7330fe76..27f5040e1877 100644 --- a/test/SemaCXX/empty-class-layout.cpp +++ b/test/SemaCXX/empty-class-layout.cpp @@ -2,6 +2,8 @@ #define SA(n, p) int a##n[(p) ? 1 : -1] +namespace Test0 { + struct A { int a; }; SA(0, sizeof(A) == 4); @@ -66,3 +68,19 @@ SA(11, sizeof(S7) == 8); struct S8 : Empty, A { }; SA(12, sizeof(S8) == 4); + +} + +namespace Test1 { + +// Test that we don't try to place both A subobjects at offset 0. +struct A { }; +class B { virtual void f(); }; +class C : A, virtual B { }; +struct D : virtual C { }; +struct E : virtual A { }; +class F : D, E { }; + +SA(0, sizeof(F) == 24); + +} diff --git a/test/SemaCXX/enum.cpp b/test/SemaCXX/enum.cpp index dc4a506dda21..bfb5784dd161 100644 --- a/test/SemaCXX/enum.cpp +++ b/test/SemaCXX/enum.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++98 -verify -triple x86_64-apple-darwin %s - enum E { Val1, Val2 @@ -71,3 +70,12 @@ namespace PR6061 { namespace Conditional { enum a { A }; a x(const enum a x) { return 1?x:A; } } + +namespace PR7051 { + enum E { e0 }; + void f() { + E e; + e = 1; // expected-error{{assigning to 'PR7051::E' from incompatible type 'int'}} + e |= 1; // expected-error{{assigning to 'PR7051::E' from incompatible type 'int'}} + } +} diff --git a/test/SemaCXX/flexible-array-test.cpp b/test/SemaCXX/flexible-array-test.cpp new file mode 100644 index 000000000000..02e3f83974e2 --- /dev/null +++ b/test/SemaCXX/flexible-array-test.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// pr7029 + +template <class Key, class T> struct QMap +{ + void insert(const Key &, const T &); + T v; +}; + + +template <class Key, class T> +void QMap<Key, T>::insert(const Key &, const T &avalue) +{ + v = avalue; +} + + +struct inotify_event +{ + int wd; + + // clang doesn't like '[]': + // cannot initialize a parameter of type 'void *' with an rvalue of type 'char (*)[]' + char name []; +}; + + +void foo() +{ + inotify_event event; + inotify_event* ptr = &event; + inotify_event event1 = *ptr; + *ptr = event; + QMap<int, inotify_event> eventForId; + eventForId.insert(ptr->wd, *ptr); +} + +struct S { + virtual void foo(); +}; + +struct X { + int blah; + S strings[]; // expected-error {{flexible array member 'strings' of non-POD element type 'S []'}} +}; diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp index e8275d463de5..9672a420dcae 100644 --- a/test/SemaCXX/i-c-e-cxx.cpp +++ b/test/SemaCXX/i-c-e-cxx.cpp @@ -17,7 +17,7 @@ void f() { int a() { const int t=t; // expected-note {{subexpression not valid}} - switch(1) { + switch(1) { // expected-warning {{no case matching constant switch condition '1'}} case t:; // expected-error {{not an integer constant expression}} } } diff --git a/test/SemaCXX/implicit-virtual-member-functions.cpp b/test/SemaCXX/implicit-virtual-member-functions.cpp index cb245011a873..f6082e5699cc 100644 --- a/test/SemaCXX/implicit-virtual-member-functions.cpp +++ b/test/SemaCXX/implicit-virtual-member-functions.cpp @@ -21,9 +21,9 @@ C::C() { } // expected-note {{implicit default destructor for 'C' first require struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}} void operator delete(void *, int); // expected-note {{'operator delete' declared here}} -}; // expected-note {{implicit default destructor for 'D' first required here}} +}; void f() { - new D; + new D; // expected-note {{implicit default destructor for 'D' first required here}} } diff --git a/test/SemaCXX/invalid-instantiated-field-decl.cpp b/test/SemaCXX/invalid-instantiated-field-decl.cpp new file mode 100644 index 000000000000..8b26489d94d1 --- /dev/null +++ b/test/SemaCXX/invalid-instantiated-field-decl.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template <typename T> +class SmallVectorImpl { +public: + explicit SmallVectorImpl(unsigned N) { + } + + ~SmallVectorImpl() { } + +}; + +template <typename T, unsigned N> +class SmallVector : public SmallVectorImpl<T> { + typedef typename SmallVectorImpl<T>::U U; // expected-error {{no type named 'U' in 'SmallVectorImpl<CallSite>'}} + enum { + + MinUs = (static_cast<unsigned int>(sizeof(T))*N + // expected-error {{invalid application of 'sizeof' to an incomplete type 'CallSite'}} + static_cast<unsigned int>(sizeof(U)) - 1) / + static_cast<unsigned int>(sizeof(U)), + NumInlineEltsElts = MinUs + }; + U InlineElts[NumInlineEltsElts]; +public: + SmallVector() : SmallVectorImpl<T>(NumInlineEltsElts) { + } + +}; + +class CallSite; // expected-note {{forward declaration of 'CallSite'}} +class InlineFunctionInfo { +public: + explicit InlineFunctionInfo() {} + SmallVector<CallSite, 2> DevirtualizedCalls; // expected-note {{in instantiation of template class 'SmallVector<CallSite, 2>' requested}} +}; diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index be25cbdb7ed0..9d5cd2fc9273 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -157,3 +157,20 @@ namespace pr6783 { return object->*p2m; // expected-error {{left hand operand to ->*}} } } + +namespace PR7176 { + namespace base + { + struct Process + { }; + struct Continuous : Process + { + bool cond(); + }; + } + + typedef bool( base::Process::*Condition )(); + + void m() + { (void)(Condition) &base::Continuous::cond; } +} diff --git a/test/SemaCXX/namespace-alias.cpp b/test/SemaCXX/namespace-alias.cpp index 1c3da3c656a6..52cae2e92f5a 100644 --- a/test/SemaCXX/namespace-alias.cpp +++ b/test/SemaCXX/namespace-alias.cpp @@ -84,6 +84,26 @@ namespace K { } } +namespace { + class C1; +} +namespace { + class C1; +} +C1 *pc1 = 0; + +namespace N { + namespace { + class C2; + } +} +namespace N { + namespace { + class C2; + } +} +N::C2 *pc2 = 0; + // PR6341 namespace A = N; namespace N { } diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index 59a8e8c45dc7..0dc1097e3867 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -228,3 +228,19 @@ namespace test3 { A::execute(path); // expected-error {{incomplete type 'test3::A' named in nested name specifier}} } } + +namespace PR7133 { + namespace A { + class Foo; + } + + namespace A { + namespace B { + bool foo(Foo &); + } + } + + bool A::B::foo(Foo &) { + return false; + } +} diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index 763ed2c7b4d6..3f1da0292b4a 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -24,6 +24,8 @@ void* operator new(size_t, int*); // expected-note 3 {{candidate}} void* operator new(size_t, float*); // expected-note 3 {{candidate}} void* operator new(size_t, S); // expected-note 2 {{candidate}} +struct foo { }; + void good_news() { int *pi = new int; @@ -43,6 +45,14 @@ void good_news() pi = new (S(1.0f, 2)) int; (void)new int[true]; + + // PR7147 + typedef int a[2]; + foo* f1 = new foo; + foo* f2 = new foo[2]; + typedef foo x[2]; + typedef foo y[2][2]; + x* f3 = new y; } struct abstract { @@ -93,7 +103,7 @@ void bad_deletes() delete 0; // expected-error {{cannot delete expression of type 'int'}} delete [0] (int*)0; // expected-error {{expected ']'}} \ // expected-note {{to match this '['}} - delete (void*)0; // expected-error {{cannot delete expression}} + delete (void*)0; // expected-warning {{cannot delete expression with pointer-to-'void' type 'void *'}} delete (T*)0; // expected-warning {{deleting pointer to incomplete type}} ::S::delete (int*)0; // expected-error {{expected unqualified-id}} } @@ -235,6 +245,9 @@ namespace Test1 { void f() { (void)new int[10](1, 2); // expected-error {{array 'new' cannot have initialization arguments}} + + typedef int T[10]; + (void)new T(1, 2); // expected-error {{array 'new' cannot have initialization arguments}} } template<typename T> diff --git a/test/SemaCXX/offsetof.cpp b/test/SemaCXX/offsetof.cpp index 47c3f22a0ed3..639d7faa8e96 100644 --- a/test/SemaCXX/offsetof.cpp +++ b/test/SemaCXX/offsetof.cpp @@ -26,7 +26,7 @@ struct HasArray { // Constant and non-constant offsetof expressions void test_ice(int i) { int array0[__builtin_offsetof(HasArray, array[5])]; - int array1[__builtin_offsetof(HasArray, array[i])]; // expected-error{{variable length arrays are not permitted in C++}} + int array1[__builtin_offsetof(HasArray, array[i])]; } // Bitfields diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp index 79c74cec4947..29133c7c7ff1 100644 --- a/test/SemaCXX/overload-call.cpp +++ b/test/SemaCXX/overload-call.cpp @@ -430,3 +430,33 @@ namespace PR6177 { void g() { f(""); } // expected-error{{volatile lvalue reference to type 'bool const volatile' cannot bind to a value of unrelated type 'char const [1]'}} } + +namespace PR7095 { + struct X { }; + + struct Y { + operator const X*(); + + private: + operator X*(); + }; + + void f(const X *); + void g(Y y) { f(y); } +} + +namespace PR7224 { + class A {}; + class B : public A {}; + + int &foo(A *const d); + float &foo(const A *const d); + + void bar() + { + B *const d = 0; + B const *const d2 = 0; + int &ir = foo(d); + float &fr = foo(d2); + } +} diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp index e40ea01a9b99..a7aafe41c392 100644 --- a/test/SemaCXX/references.cpp +++ b/test/SemaCXX/references.cpp @@ -115,3 +115,18 @@ void test10() { int &c = ev.x; // expected-error{{non-const reference cannot bind to vector element}} const int &d = ev.x; } + +namespace PR7149 { + template<typename T> struct X0 + { + T& first; + X0(T& p1) : first(p1) { } + }; + + + void f() + { + int p1[1]; + X0< const int[1]> c(p1); + } +} diff --git a/test/SemaCXX/return-noreturn.cpp b/test/SemaCXX/return-noreturn.cpp new file mode 100644 index 000000000000..9242d1240ab6 --- /dev/null +++ b/test/SemaCXX/return-noreturn.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify -Wmissing-noreturn -Wno-unreachable-code + +// A destructor may be marked noreturn and should still influence the CFG. +namespace PR6884 { + struct abort_struct { + abort_struct() {} // Make this non-POD so the destructor is invoked. + ~abort_struct() __attribute__((noreturn)); + }; + + int f() { + abort_struct(); + } + + int f2() { + abort_struct s; + } // expected-warning{{control reaches end of non-void function}} +} diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp new file mode 100644 index 000000000000..cef64f6322c5 --- /dev/null +++ b/test/SemaCXX/scope-check.cpp @@ -0,0 +1,123 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-unreachable-code + +namespace test0 { + struct D { ~D(); }; + + int f(bool b) { + if (b) { + D d; + goto end; + } + + end: + return 1; + } +} + +namespace test1 { + struct C { C(); }; + + int f(bool b) { + if (b) + goto foo; // expected-error {{illegal goto into protected scope}} + C c; // expected-note {{jump bypasses variable initialization}} + foo: + return 1; + } +} + +namespace test2 { + struct C { C(); }; + + int f(void **ip) { + static void *ips[] = { &&lbl1, &&lbl2 }; + + C c; + goto *ip; + lbl1: + return 0; + lbl2: + return 1; + } +} + +namespace test3 { + struct C { C(); }; + + int f(void **ip) { + static void *ips[] = { &&lbl1, &&lbl2 }; + + goto *ip; + lbl1: { + C c; + return 0; + } + lbl2: + return 1; + } +} + +namespace test4 { + struct C { C(); }; + struct D { ~D(); }; + + int f(void **ip) { + static void *ips[] = { &&lbl1, &&lbl2 }; + + C c0; + + goto *ip; // expected-warning {{indirect goto might cross protected scopes}} + C c1; // expected-note {{jump bypasses variable initialization}} + lbl1: // expected-note {{possible target of indirect goto}} + return 0; + lbl2: + return 1; + } +} + +namespace test5 { + struct C { C(); }; + struct D { ~D(); }; + + int f(void **ip) { + static void *ips[] = { &&lbl1, &&lbl2 }; + C c0; + + goto *ip; + lbl1: // expected-note {{possible target of indirect goto}} + return 0; + lbl2: + if (ip[1]) { + D d; // expected-note {{jump exits scope of variable with non-trivial destructor}} + ip += 2; + goto *ip; // expected-warning {{indirect goto might cross protected scopes}} + } + return 1; + } +} + +namespace test6 { + struct C { C(); }; + + unsigned f(unsigned s0, unsigned s1, void **ip) { + static void *ips[] = { &&lbl1, &&lbl2, &&lbl3, &&lbl4 }; + C c0; + + goto *ip; + lbl1: + s0++; + goto *++ip; + lbl2: + s0 -= s1; + goto *++ip; + lbl3: { + unsigned tmp = s0; + s0 = s1; + s1 = tmp; + goto *++ip; + } + lbl4: + return s0; + } +} + diff --git a/test/SemaCXX/switch.cpp b/test/SemaCXX/switch.cpp index c256960af1da..fc13630bbf12 100644 --- a/test/SemaCXX/switch.cpp +++ b/test/SemaCXX/switch.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum %s void test() { bool x = true; @@ -40,3 +40,20 @@ void x3(C &c) { switch (c) { // expected-error{{incomplete class type}} } } + +namespace test3 { + enum En { A, B, C }; + template <En how> void foo() { + int x = 0, y = 5; + + switch (how) { //expected-warning {{no case matching constant switch condition '2'}} + case A: x *= y; break; + case B: x += y; break; + // No case for C, but it's okay because we have a constant condition. + } + } + + template void foo<A>(); + template void foo<B>(); + template void foo<C>(); //expected-note {{in instantiation}} +} diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp index d31f1f7196aa..55ec9418cd47 100644 --- a/test/SemaCXX/vararg-non-pod.cpp +++ b/test/SemaCXX/vararg-non-pod.cpp @@ -88,3 +88,13 @@ void test_typeid(Base &base) { (void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'Base' through variadic function; call will abort at runtime}} (void)typeid(eat_base(base)); // okay } + + +// rdar://7985267 - Shouldn't warn, doesn't actually use __builtin_va_start is +// magic. + +void t6(Foo somearg, ... ) { + __builtin_va_list list; + __builtin_va_start(list, somearg); +} + diff --git a/test/SemaCXX/vector.cpp b/test/SemaCXX/vector.cpp new file mode 100644 index 000000000000..b548865553c2 --- /dev/null +++ b/test/SemaCXX/vector.cpp @@ -0,0 +1,188 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s +typedef char char16 __attribute__ ((__vector_size__ (16))); +typedef long long longlong16 __attribute__ ((__vector_size__ (16))); +typedef char char16_e __attribute__ ((__ext_vector_type__ (16))); +typedef long long longlong16_e __attribute__ ((__ext_vector_type__ (2))); + +// Test overloading and function calls with vector types. +void f0(char16); + +void f0_test(char16 c16, longlong16 ll16, char16_e c16e, longlong16_e ll16e) { + f0(c16); + f0(ll16); + f0(c16e); + f0(ll16e); +} + +int &f1(char16); // expected-note 2{{candidate function}} +float &f1(longlong16); // expected-note 2{{candidate function}} + +void f1_test(char16 c16, longlong16 ll16, char16_e c16e, longlong16_e ll16e) { + int &ir1 = f1(c16); + float &fr1 = f1(ll16); + f1(c16e); // expected-error{{call to 'f1' is ambiguous}} + f1(ll16e); // expected-error{{call to 'f1' is ambiguous}} +} + +void f2(char16_e); // expected-note{{no known conversion from 'longlong16_e' to 'char16_e' for 1st argument}} \ + // expected-note{{candidate function not viable: no known conversion from 'convertible_to<longlong16_e>' to 'char16_e' for 1st argument}} + +void f2_test(char16 c16, longlong16 ll16, char16_e c16e, longlong16_e ll16e) { + f2(c16); + f2(ll16); + f2(c16e); + f2(ll16e); // expected-error{{no matching function}} + f2('a'); + f2(17); +} + +// Test the conditional operator with vector types. +void conditional(bool Cond, char16 c16, longlong16 ll16, char16_e c16e, + longlong16_e ll16e) { + // Conditional operators with the same type. + __typeof__(Cond? c16 : c16) *c16p1 = &c16; + __typeof__(Cond? ll16 : ll16) *ll16p1 = &ll16; + __typeof__(Cond? c16e : c16e) *c16ep1 = &c16e; + __typeof__(Cond? ll16e : ll16e) *ll16ep1 = &ll16e; + + // Conditional operators with similar types. + __typeof__(Cond? c16 : c16e) *c16ep2 = &c16e; + __typeof__(Cond? c16e : c16) *c16ep3 = &c16e; + __typeof__(Cond? ll16 : ll16e) *ll16ep2 = &ll16e; + __typeof__(Cond? ll16e : ll16) *ll16ep3 = &ll16e; + + // Conditional operators with incompatible types. + (void)(Cond? c16 : ll16); // expected-error{{can't convert between vector values}} + (void)(Cond? ll16e : c16e); // expected-error{{can't convert between vector values}} + (void)(Cond? ll16e : c16); // expected-error{{can't convert between vector values}} +} + +// Test C++ cast'ing of vector types. +void casts(longlong16 ll16, longlong16_e ll16e) { + // C-style casts. + (void)(char16)ll16; + (void)(char16_e)ll16; + (void)(longlong16)ll16; + (void)(longlong16_e)ll16; + (void)(char16)ll16e; + (void)(char16_e)ll16e; + (void)(longlong16)ll16e; + (void)(longlong16_e)ll16e; + + // Function-style casts. + (void)char16(ll16); + (void)char16_e(ll16); + (void)longlong16(ll16); + (void)longlong16_e(ll16); + (void)char16(ll16e); + (void)char16_e(ll16e); + (void)longlong16(ll16e); + (void)longlong16_e(ll16e); + + // static_cast + (void)static_cast<char16>(ll16); + (void)static_cast<char16_e>(ll16); + (void)static_cast<longlong16>(ll16); + (void)static_cast<longlong16_e>(ll16); + (void)static_cast<char16>(ll16e); + (void)static_cast<char16_e>(ll16e); // expected-error{{static_cast from 'longlong16_e' to 'char16_e' is not allowed}} + (void)static_cast<longlong16>(ll16e); + (void)static_cast<longlong16_e>(ll16e); + + // reinterpret_cast + (void)reinterpret_cast<char16>(ll16); + (void)reinterpret_cast<char16_e>(ll16); + (void)reinterpret_cast<longlong16>(ll16); + (void)reinterpret_cast<longlong16_e>(ll16); + (void)reinterpret_cast<char16>(ll16e); + (void)reinterpret_cast<char16_e>(ll16e); + (void)reinterpret_cast<longlong16>(ll16e); + (void)reinterpret_cast<longlong16_e>(ll16e); +} + +template<typename T> +struct convertible_to { // expected-note 3 {{candidate function (the implicit copy assignment operator)}} + operator T() const; +}; + +void test_implicit_conversions(bool Cond, char16 c16, longlong16 ll16, + char16_e c16e, longlong16_e ll16e, + convertible_to<char16> to_c16, + convertible_to<longlong16> to_ll16, + convertible_to<char16_e> to_c16e, + convertible_to<longlong16_e> to_ll16e, + convertible_to<char16&> rto_c16, + convertible_to<char16_e&> rto_c16e) { + f0(to_c16); + f0(to_ll16); + f0(to_c16e); + f0(to_ll16e); + f2(to_c16); + f2(to_ll16); + f2(to_c16e); + f2(to_ll16e); // expected-error{{no matching function}} + + (void)(c16 == c16e); + (void)(c16 == to_c16); + (void)+to_c16; + (void)-to_c16; + (void)~to_c16; + (void)(to_c16 == to_c16e); + (void)(to_c16 != to_c16e); + (void)(to_c16 < to_c16e); + (void)(to_c16 <= to_c16e); + (void)(to_c16 > to_c16e); + (void)(to_c16 >= to_c16e); + (void)(to_c16 + to_c16); + (void)(to_c16 - to_c16); + (void)(to_c16 * to_c16); + (void)(to_c16 / to_c16); + (void)(rto_c16 = to_c16); // expected-error{{no viable overloaded '='}} + (void)(rto_c16 += to_c16); + (void)(rto_c16 -= to_c16); + (void)(rto_c16 *= to_c16); + (void)(rto_c16 /= to_c16); + + (void)+to_c16e; + (void)-to_c16e; + (void)~to_c16e; + (void)(to_c16e == to_c16e); + (void)(to_c16e != to_c16e); + (void)(to_c16e < to_c16e); + (void)(to_c16e <= to_c16e); + (void)(to_c16e > to_c16e); + (void)(to_c16e >= to_c16e); + (void)(to_c16e + to_c16); + (void)(to_c16e - to_c16); + (void)(to_c16e * to_c16); + (void)(to_c16e / to_c16); + (void)(rto_c16e = to_c16); // expected-error{{no viable overloaded '='}} + (void)(rto_c16e += to_c16); + (void)(rto_c16e -= to_c16); + (void)(rto_c16e *= to_c16); + (void)(rto_c16e /= to_c16); + + (void)+to_c16; + (void)-to_c16; + (void)~to_c16; + (void)(to_c16 == to_c16e); + (void)(to_c16 != to_c16e); + (void)(to_c16 < to_c16e); + (void)(to_c16 <= to_c16e); + (void)(to_c16 > to_c16e); + (void)(to_c16 >= to_c16e); + (void)(to_c16 + to_c16e); + (void)(to_c16 - to_c16e); + (void)(to_c16 * to_c16e); + (void)(to_c16 / to_c16e); + (void)(rto_c16 = c16e); // expected-error{{no viable overloaded '='}} + (void)(rto_c16 += to_c16e); // expected-error{{expression is not assignable}} + (void)(rto_c16 -= to_c16e); // expected-error{{expression is not assignable}} + (void)(rto_c16 *= to_c16e); // expected-error{{expression is not assignable}} + (void)(rto_c16 /= to_c16e); // expected-error{{expression is not assignable}} + + (void)(Cond? to_c16 : to_c16e); + (void)(Cond? to_ll16e : to_ll16); + (void)(Cond? to_c16 : to_ll16); // expected-error{{can't convert between vector values of different size}} + (void)(Cond? to_c16e : to_ll16e); // expected-error{{can't convert between vector values of different size}} +} diff --git a/test/SemaCXX/virtual-member-functions-key-function.cpp b/test/SemaCXX/virtual-member-functions-key-function.cpp index 97164d93affc..09a30b93605e 100644 --- a/test/SemaCXX/virtual-member-functions-key-function.cpp +++ b/test/SemaCXX/virtual-member-functions-key-function.cpp @@ -4,17 +4,17 @@ struct A { }; struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}} - B() { } + B() { } // expected-note {{implicit default destructor for 'B' first required here}} void operator delete(void *, int); // expected-note {{'operator delete' declared here}} -}; // expected-note {{implicit default destructor for 'B' first required here}} +}; struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}} void operator delete(void *, int); // expected-note {{'operator delete' declared here}} -}; // expected-note {{implicit default destructor for 'C' first required here}} +}; void f() { - (void)new B; - (void)new C; + (void)new B; + (void)new C; // expected-note {{implicit default destructor for 'C' first required here}} } // Make sure that the key-function computation is consistent when the diff --git a/test/SemaCXX/warn-missing-noreturn.cpp b/test/SemaCXX/warn-missing-noreturn.cpp index 8016c3da5cc5..f2f9b2e2b751 100644 --- a/test/SemaCXX/warn-missing-noreturn.cpp +++ b/test/SemaCXX/warn-missing-noreturn.cpp @@ -36,3 +36,17 @@ namespace test1 { while (condition()) {} } } + + +// <rdar://problem/7880658> - This test case previously had a false "missing return" +// warning. +struct R7880658 { + R7880658 &operator++(); + bool operator==(const R7880658 &) const; + bool operator!=(const R7880658 &) const; +}; + +void f_R7880658(R7880658 f, R7880658 l) { // no-warning + for (; f != l; ++f) { + } +} diff --git a/test/SemaCXX/warn-reorder-ctor-initialization.cpp b/test/SemaCXX/warn-reorder-ctor-initialization.cpp index 3ff01af3627c..8c254e5515bf 100644 --- a/test/SemaCXX/warn-reorder-ctor-initialization.cpp +++ b/test/SemaCXX/warn-reorder-ctor-initialization.cpp @@ -120,3 +120,13 @@ namespace test3 { }; }; } + +namespace PR7179 { + struct X + { + struct Y + { + template <class T> Y(T x) : X(x) { } + }; + }; +} diff --git a/test/SemaCXX/warn-weak-vtables.cpp b/test/SemaCXX/warn-weak-vtables.cpp index 39333c108ae8..c0cfd74a3e52 100644 --- a/test/SemaCXX/warn-weak-vtables.cpp +++ b/test/SemaCXX/warn-weak-vtables.cpp @@ -18,4 +18,14 @@ void f() { struct A { virtual void f() { } }; + + A *a; + a->f(); +} + +// Use the vtables +void uses(A &a, B<int> &b, C &c) { + a.f(); + b.f(); + c.f(); } diff --git a/test/SemaObjC/block-attr.m b/test/SemaObjC/block-attr.m index c89aed4bb60d..de203e711ede 100644 --- a/test/SemaObjC/block-attr.m +++ b/test/SemaObjC/block-attr.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-gc-only %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-gc-only %s @interface Thing {} diff --git a/test/SemaObjC/error-property-gc-attr.m b/test/SemaObjC/error-property-gc-attr.m index a36170475bc2..661638c52e06 100644 --- a/test/SemaObjC/error-property-gc-attr.m +++ b/test/SemaObjC/error-property-gc-attr.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s +// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s @interface INTF { @@ -11,7 +12,7 @@ } @property (assign) __weak id pweak; @property (assign) __weak id WID; -@property (assign) __strong id not; +@property (assign) __strong id NOT; @property (assign) id ID; @property (assign) INTF* AWEAK; @property (assign) __weak INTF* WI; @@ -19,7 +20,7 @@ @implementation INTF @synthesize pweak=IVAR; // expected-error {{existing ivar 'IVAR' for __weak property 'pweak' must be __weak}} -@synthesize not=II; // expected-error {{existing ivar 'II' for a __strong property 'not' must be garbage collectable}} +@synthesize NOT=II; // expected-error {{existing ivar 'II' for a __strong property 'NOT' must be garbage collectable}} @synthesize WID; @synthesize ID; @synthesize AWEAK; // expected-error {{existing ivar 'AWEAK' for a __strong property 'AWEAK' must be garbage collectable}} diff --git a/test/SemaObjC/method-conflict.m b/test/SemaObjC/method-conflict.m index 08fdfc017ccc..5dc886fb7fd2 100644 --- a/test/SemaObjC/method-conflict.m +++ b/test/SemaObjC/method-conflict.m @@ -53,3 +53,14 @@ typedef NSUInteger XDSourceLanguage; return 0; } @end + +// rdar: // 8006060 +@interface Bar +- (void)foo:(id)format, ...; // expected-note {{previous declaration is here}} +- (void)foo1:(id)format; // expected-note {{previous declaration is here}} +@end +@implementation Bar +- (void)foo:(id)format {}; // expected-warning {{conflicting variadic declaration of method and its implementation}} +- (void)foo1:(id)format, ... {}; // expected-warning {{conflicting variadic declaration of method and its implementation}} +@end + diff --git a/test/SemaObjC/objc2-warn-weak-decl.m b/test/SemaObjC/objc2-warn-weak-decl.m index 76b542de94a6..22a3fca91ba5 100644 --- a/test/SemaObjC/objc2-warn-weak-decl.m +++ b/test/SemaObjC/objc2-warn-weak-decl.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s +// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s struct S { __weak id p; // expected-warning {{__weak attribute cannot be specified on a field declaration}} }; diff --git a/test/SemaObjC/warn-assign-property-nscopying.m b/test/SemaObjC/warn-assign-property-nscopying.m index 953814cdce1b..1bdb4f0de93e 100644 --- a/test/SemaObjC/warn-assign-property-nscopying.m +++ b/test/SemaObjC/warn-assign-property-nscopying.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fobjc-gc -fsyntax-only -verify %s +// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -fsyntax-only -verify %s @protocol NSCopying @end diff --git a/test/SemaObjC/warn-weak-field.m b/test/SemaObjC/warn-weak-field.m index f20691c18696..ead454a04a37 100644 --- a/test/SemaObjC/warn-weak-field.m +++ b/test/SemaObjC/warn-weak-field.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s +// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s struct S { __weak id w; // expected-warning {{__weak attribute cannot be specified on a field declaration}} diff --git a/test/SemaObjCXX/const-cast.mm b/test/SemaObjCXX/const-cast.mm new file mode 100644 index 000000000000..933fd47de7ca --- /dev/null +++ b/test/SemaObjCXX/const-cast.mm @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@class Foo; + +void test() { + const Foo *foo1 = 0; + Foo *foo2 = foo1; // expected-error {{cannot initialize}} +} + +void test1() { + const Foo *foo1 = 0; + Foo *foo2 = const_cast<Foo*>(foo1); +} diff --git a/test/SemaObjCXX/conversion-to-objc-pointer-2.mm b/test/SemaObjCXX/conversion-to-objc-pointer-2.mm new file mode 100644 index 000000000000..5277d101f588 --- /dev/null +++ b/test/SemaObjCXX/conversion-to-objc-pointer-2.mm @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// rdar: // 7963410 + +@protocol NSObject @end +@interface NSObject +- (id)init; +- (id) alloc; +- (id) autorelease; +@end + +template<class T> +class TNSAutoRef +{ +public: + TNSAutoRef(T t) + : fRef(t) + { } + + ~TNSAutoRef() + { } + + operator T() const + { return fRef; } + +private: + T fRef; +}; + + +#pragma mark - + + +@protocol TFooProtocol <NSObject> + +- (void) foo; +@end + + +#pragma mark - + + +@interface TFoo : NSObject + +- (void) setBlah: (id<TFooProtocol>)blah; +@end + + +#pragma mark - + + +@implementation TFoo + +- (void) setBlah: (id<TFooProtocol>)blah + { } +@end + + +#pragma mark - + + +@interface TBar : NSObject + +- (void) setBlah: (id)blah; +@end + +#pragma mark - + + +@implementation TBar + +- (void) setBlah: (id)blah + { } +@end + + +#pragma mark - + + +int main (int argc, const char * argv[]) { + + NSObject* object1 = [[[NSObject alloc] init] autorelease]; + TNSAutoRef<NSObject*> object2([[NSObject alloc] init]); + TNSAutoRef<TBar*> bar([[TBar alloc] init]); + [bar setBlah: object1]; // <== Does not compile. It should. + [bar setBlah: object2]; // <== Does not compile. It should. + return 0; +} diff --git a/test/SemaObjCXX/conversion-to-objc-pointer.mm b/test/SemaObjCXX/conversion-to-objc-pointer.mm new file mode 100644 index 000000000000..235aaac8d09c --- /dev/null +++ b/test/SemaObjCXX/conversion-to-objc-pointer.mm @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// rdar: // 7963410 + +template<class T> +class TNSAutoRef +{ +public: + TNSAutoRef(T t) + : fRef(t) + { } + + ~TNSAutoRef() + { } + + operator T() const + { return fRef; } + + T Get() const + { return fRef; } + +private: + T fRef; +}; + +@interface NSObject +- (id) alloc; +- (id)init; +@end + +@interface TFoo : NSObject +- (void) foo; +@end + +@implementation TFoo +- (void) foo {} +@end + +@interface TBar : NSObject +- (void) foo; +@end + +@implementation TBar +- (void) foo {} +@end + +int main () { + TNSAutoRef<TBar*> bar([[TBar alloc] init]); + [bar foo]; + return 0; +} diff --git a/test/SemaObjCXX/deduction.mm b/test/SemaObjCXX/deduction.mm new file mode 100644 index 000000000000..6dd449d6ea75 --- /dev/null +++ b/test/SemaObjCXX/deduction.mm @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@class NSString; + +// Reduced from WebKit. +namespace test0 { + template <typename T> struct RemovePointer { + typedef T Type; + }; + + template <typename T> struct RemovePointer<T*> { + typedef T Type; + }; + + template <typename T> struct RetainPtr { + typedef typename RemovePointer<T>::Type ValueType; + typedef ValueType* PtrType; + RetainPtr(PtrType ptr); + }; + + void test(NSString *S) { + RetainPtr<NSString*> ptr(S); + } + + void test(id S) { + RetainPtr<id> ptr(S); + } +} + +@class Test1Class; +@protocol Test1Protocol; +namespace test1 { + template <typename T> struct RemovePointer { + typedef T type; + }; + template <typename T> struct RemovePointer<T*> { + typedef T type; + }; + template <typename A, typename B> struct is_same {}; + template <typename A> struct is_same<A,A> { + static void foo(); + }; + template <typename T> struct tester { + void test() { + is_same<T, typename RemovePointer<T>::type*>::foo(); // expected-error 2 {{no member named 'foo'}} + } + }; + + template struct tester<id>; + template struct tester<id<Test1Protocol> >; + template struct tester<Class>; + template struct tester<Class<Test1Protocol> >; + template struct tester<Test1Class*>; + template struct tester<Test1Class<Test1Protocol>*>; + + template struct tester<Test1Class>; // expected-note {{in instantiation}} + template struct tester<Test1Class<Test1Protocol> >; // expected-note {{in instantiation}} +} diff --git a/test/SemaObjCXX/ivar-construct.mm b/test/SemaObjCXX/ivar-construct.mm new file mode 100644 index 000000000000..da066e965971 --- /dev/null +++ b/test/SemaObjCXX/ivar-construct.mm @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +struct Y { + Y(); + +private: + ~Y(); // expected-note 3{{declared private here}} +}; + +template<typename T> +struct X : T { }; // expected-error 2{{private destructor}} + +struct Z; // expected-note{{forward declaration}} + +@interface A { + X<Y> x; // expected-note{{implicit default destructor}} + Y y; // expected-error{{private destructor}} +} +@end + +@implementation A // expected-note{{implicit default constructor}} +@end + +@interface B { + Z z; // expected-error{{incomplete type}} +} +@end + +@implementation B +@end diff --git a/test/SemaObjCXX/ivar-struct.mm b/test/SemaObjCXX/ivar-struct.mm new file mode 100644 index 000000000000..3f9c7eb1a503 --- /dev/null +++ b/test/SemaObjCXX/ivar-struct.mm @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +@interface A { + struct X { + int x, y; + } X; +} +@end diff --git a/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm b/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm new file mode 100644 index 000000000000..7be5f17daa80 --- /dev/null +++ b/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s +@interface INTF @end + +extern INTF* p2; +extern __strong INTF* p2; + +extern __strong id p1; +extern id p1; + +extern id CFRunLoopGetMain(); +extern __strong id CFRunLoopGetMain(); + +extern __strong id CFRunLoopGetMain2(); +extern id CFRunLoopGetMain2(); + +extern INTF* CFRunLoopGetMain3(); +extern __strong INTF* CFRunLoopGetMain3(); + +extern __strong INTF* CFRunLoopGetMain4(); +extern INTF* CFRunLoopGetMain4(); + +typedef id ID; +extern ID CFRunLoopGetMain5(); +extern __strong id CFRunLoopGetMain5(); + +extern __strong id CFRunLoopGetMain6(); +extern ID CFRunLoopGetMain6(); + +extern ID CFRunLoopGetMain7(); +extern __strong ID CFRunLoopGetMain7(); + +extern __strong ID CFRunLoopGetMain8(); +extern ID CFRunLoopGetMain8(); + +extern __weak id WLoopGetMain(); // expected-note {{previous declaration is here}} +extern id WLoopGetMain(); // expected-error {{functions that differ only in their return type cannot be overloaded}} + +extern id p3; // expected-note {{previous definition is here}} +extern __weak id p3; // expected-error {{redefinition of 'p3' with a different type}} + +extern void *p4; // expected-note {{previous definition is here}} +extern void * __strong p4; // expected-error {{redefinition of 'p4' with a different type}} + +extern id p5; +extern __strong id p5; + +extern char* __strong p6; // expected-note {{previous definition is here}} +extern char* p6; // expected-error {{redefinition of 'p6' with a different type}} + +extern __strong char* p7; // expected-note {{previous definition is here}} +extern char* p7; // expected-error {{redefinition of 'p7' with a different type}} diff --git a/test/SemaObjCXX/static-cast.mm b/test/SemaObjCXX/static-cast.mm new file mode 100644 index 000000000000..e2827028de59 --- /dev/null +++ b/test/SemaObjCXX/static-cast.mm @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@protocol NSTextViewDelegate; + +@interface NSResponder @end + +class AutoreleaseObject +{ +public: + AutoreleaseObject(); + ~AutoreleaseObject(); + + + AutoreleaseObject& operator=(NSResponder* inValue); + AutoreleaseObject& operator=(const AutoreleaseObject& inValue); + + AutoreleaseObject(const AutoreleaseObject& inValue); + + operator NSResponder*() const; +}; + + +void InvokeSaveFocus() +{ + AutoreleaseObject mResolvedFirstResponder; + id<NSTextViewDelegate> Mydelegate; + mResolvedFirstResponder = static_cast<NSResponder*>(Mydelegate); +} + diff --git a/test/SemaObjCXX/vla.mm b/test/SemaObjCXX/vla.mm index 9c6fc54f817a..d6da1c0cf40e 100644 --- a/test/SemaObjCXX/vla.mm +++ b/test/SemaObjCXX/vla.mm @@ -6,7 +6,7 @@ @end void test(Data *d) { - char buffer[[d length]]; // expected-error{{variable length arrays are not permitted in C++}} + char buffer[[d length]]; [d getData:buffer]; } diff --git a/test/SemaObjCXX/void_to_obj.mm b/test/SemaObjCXX/void_to_obj.mm index 52510c84f139..7dca9faa8544 100644 --- a/test/SemaObjCXX/void_to_obj.mm +++ b/test/SemaObjCXX/void_to_obj.mm @@ -9,3 +9,18 @@ void func() { obj = vv; // expected-error{{assigning to 'XX *' from incompatible type 'void *'}} } + +// <rdar://problem/7952457> +@interface I +{ + void* delegate; +} +- (I*) Meth; +- (I*) Meth1; +@end + +@implementation I +- (I*) Meth { return static_cast<I*>(delegate); } +- (I*) Meth1 { return reinterpret_cast<I*>(delegate); } +@end + diff --git a/test/SemaTemplate/attributes.cpp b/test/SemaTemplate/attributes.cpp new file mode 100644 index 000000000000..b696c5cd9840 --- /dev/null +++ b/test/SemaTemplate/attributes.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template<int N> +struct X { + struct __attribute__((__aligned__((N)))) Aligned { }; // expected-error{{'aligned' attribute requires integer constant}} + + int __attribute__((__address_space__(N))) *ptr; // expected-error{{attribute requires 1 argument(s)}} +}; diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp index 45637484f0fd..c631dd71d174 100644 --- a/test/SemaTemplate/current-instantiation.cpp +++ b/test/SemaTemplate/current-instantiation.cpp @@ -151,3 +151,16 @@ struct X1 { X1<T*>::a = b; } }; + +namespace ConstantInCurrentInstantiation { + template<typename T> + struct X { + static const int value = 2; + static int array[value]; + }; + + template<typename T> const int X<T>::value; + + template<typename T> + int X<T>::array[X<T>::value] = { 1, 2 }; +} diff --git a/test/SemaTemplate/dependent-base-classes.cpp b/test/SemaTemplate/dependent-base-classes.cpp index d0dd9c98fa71..e64d62301ea2 100644 --- a/test/SemaTemplate/dependent-base-classes.cpp +++ b/test/SemaTemplate/dependent-base-classes.cpp @@ -6,7 +6,7 @@ struct X0 : T::template apply<U> { }; template<typename T, typename U> -struct X1 : T::apply<U> { }; // expected-error{{missing 'template' keyword prior to dependent template name 'T::apply'}} +struct X1 : T::apply<U> { }; // expected-error{{use 'template' keyword to treat 'apply' as a dependent template name}} template<typename T> struct X2 : vector<T> { }; // expected-error{{unknown template name 'vector'}} diff --git a/test/SemaTemplate/dependent-expr.cpp b/test/SemaTemplate/dependent-expr.cpp index 3f481b513691..9fa757107bdb 100644 --- a/test/SemaTemplate/dependent-expr.cpp +++ b/test/SemaTemplate/dependent-expr.cpp @@ -24,3 +24,19 @@ namespace PR6045 { (void)(k % member); } } + +namespace PR7198 { + struct A + { + ~A() { } + }; + + template<typename T> + struct B { + struct C : A {}; + void f() + { + C c = C(); + } + }; +} diff --git a/test/SemaTemplate/dependent-template-recover.cpp b/test/SemaTemplate/dependent-template-recover.cpp new file mode 100644 index 000000000000..e91ffb52539c --- /dev/null +++ b/test/SemaTemplate/dependent-template-recover.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +template<typename T, typename U, int N> +struct X { + void f(T* t) { + t->f0<U>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}} + t->f0<int>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}} + + t->operator+<U const, 1>(); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}} + t->f1<int const, 2>(); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}} + + T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}} + t->T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}} + + // FIXME: We can't recover from these yet + (*t).f2<N>(); // expected-error{{expected expression}} + (*t).f2<0>(); // expected-error{{expected expression}} + } +}; diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp index e09581223af6..feffdcf36959 100644 --- a/test/SemaTemplate/dependent-type-identity.cpp +++ b/test/SemaTemplate/dependent-type-identity.cpp @@ -70,3 +70,19 @@ struct X1 { void f8(typename N::X2<U>::template apply<T> *); void f8(typename ::Nalias::X2<type>::template apply<U_type> *); // expected-error{{redeclar}} }; + +namespace PR6851 { + template <bool v> + struct S; + + struct N { + template <bool w> + S< S<w>::cond && 1 > foo(); + }; + + struct Alien; + bool operator&&(const Alien&, const Alien&); + + template <bool w> + S< S<w>::cond && 1 > N::foo() { } +} diff --git a/test/SemaTemplate/enum-argument.cpp b/test/SemaTemplate/enum-argument.cpp index de89487bd581..7d237570678f 100644 --- a/test/SemaTemplate/enum-argument.cpp +++ b/test/SemaTemplate/enum-argument.cpp @@ -21,3 +21,16 @@ struct X0 { }; X0<int> x0i; + +namespace rdar8020920 { + template<typename T> + struct X { + enum { e0 = 32 }; + + unsigned long long bitfield : e0; + + void f(int j) { + bitfield + j; + } + }; +} diff --git a/test/SemaTemplate/instantiate-anonymous-union.cpp b/test/SemaTemplate/instantiate-anonymous-union.cpp index 7c75885788de..255454b2ebf2 100644 --- a/test/SemaTemplate/instantiate-anonymous-union.cpp +++ b/test/SemaTemplate/instantiate-anonymous-union.cpp @@ -29,3 +29,21 @@ template <typename T> struct C { }; C<int> c0(0); + +namespace PR7088 { + template<typename T> + void f() { + union { + int a; + union { + float real; + T d; + }; + }; + + a = 17; + d = 3.14; + } + + template void f<double>(); +} diff --git a/test/SemaTemplate/instantiate-attr.cpp b/test/SemaTemplate/instantiate-attr.cpp index 7fb173645932..e8291ed00d20 100644 --- a/test/SemaTemplate/instantiate-attr.cpp +++ b/test/SemaTemplate/instantiate-attr.cpp @@ -2,6 +2,12 @@ template <typename T> struct A { char a __attribute__((aligned(16))); + + struct B { + typedef T __attribute__((aligned(16))) i16; + i16 x; + }; }; int a[sizeof(A<int>) == 16 ? 1 : -1]; +int a2[sizeof(A<int>::B) == 16 ? 1 : -1]; diff --git a/test/SemaTemplate/instantiate-complete.cpp b/test/SemaTemplate/instantiate-complete.cpp index d854c9e6aacc..c13930d108c4 100644 --- a/test/SemaTemplate/instantiate-complete.cpp +++ b/test/SemaTemplate/instantiate-complete.cpp @@ -99,3 +99,32 @@ namespace TemporaryObjectCopy { template void f(int); } + +namespace PR7080 { + template <class T, class U> + class X + { + typedef char true_t; + class false_t { char dummy[2]; }; + static true_t dispatch(U); + static false_t dispatch(...); + static T trigger(); + public: + enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) }; + }; + + template <class T> + class rv : public T + { }; + + bool x = X<int, rv<int>&>::value; +} + +namespace pr7199 { + template <class T> class A; // expected-note {{template is declared here}} + template <class T> class B { + class A<T>::C field; // expected-error {{implicit instantiation of undefined template 'pr7199::A<int>'}} + }; + + template class B<int>; // expected-note {{in instantiation}} +} diff --git a/test/SemaTemplate/instantiate-declref-ice.cpp b/test/SemaTemplate/instantiate-declref-ice.cpp index e88b49447cb9..0f3c08b05620 100644 --- a/test/SemaTemplate/instantiate-declref-ice.cpp +++ b/test/SemaTemplate/instantiate-declref-ice.cpp @@ -31,5 +31,4 @@ struct X1 { template<typename T> const unsigned X1<T>::value = sizeof(T); -int array3[X1<int>::value == sizeof(int)? 1 : -1]; // expected-error{{variable length arrays are not permitted in C++}} \ -// expected-error{{variable length array declaration not allowed at file scope}} +int array3[X1<int>::value == sizeof(int)? 1 : -1]; // expected-error{{variable length array declaration not allowed at file scope}} diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp index b91b398a80e3..eaa68ddea901 100644 --- a/test/SemaTemplate/instantiate-expr-2.cpp +++ b/test/SemaTemplate/instantiate-expr-2.cpp @@ -194,6 +194,37 @@ namespace N12 { void f0(int **a) { C::f0(a); } } +namespace PR7202 { + template<typename U, typename T> + struct meta { + typedef T type; + }; + + struct X { + struct dummy; + + template<typename T> + X(T, typename meta<T, dummy*>::type = 0); + + template<typename T, typename A> + X(T, A); + }; + + template<typename T> + struct Z { }; + + template<typename T> Z<T> g(T); + + struct Y { + template<typename T> + void f(T t) { + new X(g(*this)); + } + }; + + template void Y::f(int); +} + namespace N13 { class A{ A(const A&); diff --git a/test/SemaTemplate/instantiate-expr-3.cpp b/test/SemaTemplate/instantiate-expr-3.cpp index 41a96a32e0bf..d506b19a7a97 100644 --- a/test/SemaTemplate/instantiate-expr-3.cpp +++ b/test/SemaTemplate/instantiate-expr-3.cpp @@ -63,7 +63,7 @@ template struct Conditional0<int, int, int>; template<typename T> struct StatementExpr0 { void f(T t) { - (void)({ if (t) t = t + 17; t + 12;}); // expected-error{{invalid}} + (void)({ if (t) t = t + 17; t + 12;}); // expected-error{{contextually convertible}} } }; diff --git a/test/SemaTemplate/instantiate-field.cpp b/test/SemaTemplate/instantiate-field.cpp index 60d4b21cac9e..a260635778ca 100644 --- a/test/SemaTemplate/instantiate-field.cpp +++ b/test/SemaTemplate/instantiate-field.cpp @@ -26,3 +26,58 @@ void test2(const X<float> *xf) { void test3(const X<int(int)> *xf) { (void)xf->x; // expected-note{{in instantiation of template class 'X<int (int)>' requested here}} } + +namespace PR7123 { + template <class > struct requirement_; + + template <void(*)()> struct instantiate + { }; + + template <class > struct requirement ; + struct failed ; + + template <class Model> struct requirement<failed *Model::*> + { + static void failed() + { + ((Model*)0)->~Model(); // expected-note{{in instantiation of}} + } + }; + + template <class Model> struct requirement_<void(*)(Model)> : requirement<failed *Model::*> + { }; + + template <int> struct Requires_ + { typedef void type; }; + + template <class Model> struct usage_requirements + { + ~usage_requirements() + {((Model*)0)->~Model(); } // expected-note{{in instantiation of}} + }; + + template < typename TT > struct BidirectionalIterator + { + enum + { value = 0 }; + + instantiate< requirement_<void(*)(usage_requirements<BidirectionalIterator>)>::failed> int534; // expected-note{{in instantiation of}} + + ~BidirectionalIterator() + { i--; } // expected-error{{cannot decrement value of type 'PR7123::X'}} + + TT i; + }; + + struct X + { }; + + template<typename RanIter> + typename Requires_< BidirectionalIterator<RanIter>::value >::type sort(RanIter,RanIter){} + + void f() + { + X x; + sort(x,x); + } +} diff --git a/test/SemaTemplate/instantiate-function-2.cpp b/test/SemaTemplate/instantiate-function-2.cpp index 6318facfc0ea..afca35878444 100644 --- a/test/SemaTemplate/instantiate-function-2.cpp +++ b/test/SemaTemplate/instantiate-function-2.cpp @@ -10,3 +10,13 @@ void f() { S<int> s1; S<int> s2(10); } + +namespace PR7184 { + template<typename T> + void f() { + typedef T type; + void g(int array[sizeof(type)]); + } + + template void f<int>(); +} diff --git a/test/SemaTemplate/instantiate-member-pointers.cpp b/test/SemaTemplate/instantiate-member-pointers.cpp index 2308ac541b2e..dca0f6217054 100644 --- a/test/SemaTemplate/instantiate-member-pointers.cpp +++ b/test/SemaTemplate/instantiate-member-pointers.cpp @@ -53,3 +53,15 @@ void accept_X4(X4<Member>); void test_accept_X4(X4<&Y::x> x4) { accept_X4(x4); } + +namespace ValueDepMemberPointer { + template <void (*)()> struct instantiate_function {}; + template <typename T> struct S { + static void instantiate(); + typedef instantiate_function<&S::instantiate> x; // expected-note{{instantiation}} + }; + template <typename T> void S<T>::instantiate() { + int a[(int)sizeof(T)-42]; // expected-error{{array size is negative}} + } + S<int> s; +} diff --git a/test/SemaTemplate/instantiate-non-dependent-types.cpp b/test/SemaTemplate/instantiate-non-dependent-types.cpp new file mode 100644 index 000000000000..a0005c56675a --- /dev/null +++ b/test/SemaTemplate/instantiate-non-dependent-types.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +template<typename T> +struct X1 { + static void member() { T* x = 1; } // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} +}; + +template<void(*)()> struct instantiate { }; + +template<typename T> +struct X2 { + typedef instantiate<&X1<int>::member> i; // expected-note{{in instantiation of}} +}; + +X2<int> x; diff --git a/test/SemaTemplate/instantiate-overload-candidates.cpp b/test/SemaTemplate/instantiate-overload-candidates.cpp new file mode 100644 index 000000000000..5b7e60dccfdd --- /dev/null +++ b/test/SemaTemplate/instantiate-overload-candidates.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// This is the function actually selected during overload resolution, and the +// only one defined. +template <typename T> void f(T*, int) {} + +template <typename T> struct S; +template <typename T> struct S_ : S<T> { typedef int type; }; // expected-note{{in instantiation}} +template <typename T> struct S { + // Force T to have a complete type here so we can observe instantiations with + // incomplete types. + T t; // expected-error{{field has incomplete type}} +}; + +// Provide a bad class and an overload that instantiates templates with it. +class NoDefinition; // expected-note{{forward declaration}} +template <typename T> S_<NoDefinition>::type f(T*, NoDefinition*); // expected-note{{in instantiation}} + +void test(int x) { + f(&x, 0); +} diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp index 9d25a051e8a8..54e615b4ab69 100644 --- a/test/SemaTemplate/nested-name-spec-template.cpp +++ b/test/SemaTemplate/nested-name-spec-template.cpp @@ -64,3 +64,10 @@ namespace test1 { template <class T> T pair<T>::* const pair<T>::mem_array[2] = { &pair<T>::x, &pair<T>::y }; } + +typedef int T; +namespace N1 { + template<typename T> T f0(); +} + +template<typename T> T N1::f0() { } diff --git a/test/SemaTemplate/overload-candidates.cpp b/test/SemaTemplate/overload-candidates.cpp new file mode 100644 index 000000000000..8762cc80630a --- /dev/null +++ b/test/SemaTemplate/overload-candidates.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template<typename T> +const T& min(const T&, const T&); // expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'long')}} + +void test_min() { + (void)min(1, 2l); // expected-error{{no matching function for call to 'min'}} +} + +template<typename R, typename T> +R *dyn_cast(const T&); // expected-note{{candidate template ignored: couldn't infer template argument 'R'}} + +void test_dyn_cast(int* ptr) { + (void)dyn_cast(ptr); // expected-error{{no matching function for call to 'dyn_cast'}} +} + +template<int I, typename T> + void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for template parameter 'I'}} +template<template<class T> class, typename T> + void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} + +void test_get(void *ptr) { + get<int>(ptr); // expected-error{{no matching function for call to 'get'}} +} + +template<typename T> + typename T::type get_type(const T&); // expected-note{{candidate template ignored: substitution failure [with T = int *]}} + +void test_get_type(int *ptr) { + (void)get_type(ptr); // expected-error{{no matching function for call to 'get_type'}} +} + +struct X { + template<typename T> + const T& min(const T&, const T&); // expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'long')}} +}; + +void test_X_min(X x) { + (void)x.min(1, 2l); // expected-error{{no matching member function for call to 'min'}} +} diff --git a/test/SemaTemplate/partial-spec-instantiate.cpp b/test/SemaTemplate/partial-spec-instantiate.cpp index 3156892a7234..68b4964816e4 100644 --- a/test/SemaTemplate/partial-spec-instantiate.cpp +++ b/test/SemaTemplate/partial-spec-instantiate.cpp @@ -18,3 +18,23 @@ struct X2<U*> { }; void a(char *a, char *b) {X2<char*>::f();} + +namespace WonkyAccess { + template<typename T> + struct X { + int m; + }; + + template<typename U> + class Y; + + template<typename U> + struct Y<U*> : X<U> { }; + + template<> + struct Y<float*> : X<float> { }; + + int f(Y<int*> y, Y<float*> y2) { + return y.m + y2.m; + } +} diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp index fbb41ff601a3..76244c25e824 100644 --- a/test/SemaTemplate/temp_explicit.cpp +++ b/test/SemaTemplate/temp_explicit.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wc++0x-compat %s // // Tests explicit instantiation of templates. template<typename T, typename U = T> class X0 { }; @@ -125,3 +125,27 @@ template <> // expected-warning{{extraneous template parameter list}} template <> struct Foo<int>::Bar<void> {}; + +namespace N1 { + + template<typename T> struct X7 { }; // expected-note{{here}} + + namespace Inner { + template<typename T> struct X8 { }; + } + + template struct X7<int>; + template struct Inner::X8<int>; +} + +template<typename T> struct X9 { }; // expected-note{{here}} + +template struct ::N1::Inner::X8<float>; + +namespace N2 { + using namespace N1; + + template struct X7<double>; // expected-warning{{must occur in namespace}} + + template struct X9<float>; // expected-warning{{must occur in the global}} +} diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp index b3f41be7bfad..de8d7f6c91a4 100644 --- a/test/SemaTemplate/template-id-expr.cpp +++ b/test/SemaTemplate/template-id-expr.cpp @@ -44,3 +44,41 @@ struct X { }; template struct X<3>; + +// 'template' as a disambiguator. +// PR7030 +struct Y0 { + template<typename U> + void f1(U); + + template<typename U> + static void f2(U); + + void f3(int); + + static int f4(int); + template<typename U> + static void f4(U); + + template<typename U> + void f() { + Y0::template f1<U>(0); + Y0::template f1(0); + this->template f1(0); + + Y0::template f2<U>(0); + Y0::template f2(0); + + Y0::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + Y0::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + + int x; + x = Y0::f4(0); + x = Y0::f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + + x = this->f4(0); + x = this->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + } +}; diff --git a/test/SemaTemplate/unused-variables.cpp b/test/SemaTemplate/unused-variables.cpp new file mode 100644 index 000000000000..1b9350b865dc --- /dev/null +++ b/test/SemaTemplate/unused-variables.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -fsyntax-only -Wunused -verify %s + +struct X0 { + ~X0(); +}; + +struct X1 { }; + +template<typename T> +void f() { + X0 x0; + X1 x1; // expected-warning{{unused variable 'x1'}} +} + +template<typename T, typename U> +void g() { + T t; + U u; // expected-warning{{unused variable 'u'}} +} + +template void g<X0, X1>(); // expected-note{{in instantiation of}} diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp index 59df3c22aa1c..974f66484ba1 100644 --- a/test/SemaTemplate/virtual-member-functions.cpp +++ b/test/SemaTemplate/virtual-member-functions.cpp @@ -3,7 +3,7 @@ namespace PR5557 { template <class T> struct A { A(); - virtual void anchor(); // expected-note{{instantiation}} + virtual void anchor(); virtual int a(T x); }; template<class T> A<T>::A() {} @@ -14,7 +14,7 @@ template<class T> int A<T>::a(T x) { } void f(A<int> x) { - x.anchor(); + x.anchor(); // expected-note{{instantiation}} } template<typename T> @@ -43,7 +43,7 @@ template struct Derived<int>; // expected-note {{in instantiation of member func template<typename T> struct HasOutOfLineKey { - HasOutOfLineKey() { } // expected-note{{in instantiation of member function 'HasOutOfLineKey<int>::f' requested here}} + HasOutOfLineKey() { } virtual T *f(float *fp); }; @@ -52,4 +52,35 @@ T *HasOutOfLineKey<T>::f(float *fp) { return fp; // expected-error{{cannot initialize return object of type 'int *' with an lvalue of type 'float *'}} } -HasOutOfLineKey<int> out_of_line; +HasOutOfLineKey<int> out_of_line; // expected-note{{in instantiation of member function 'HasOutOfLineKey<int>::f' requested here}} + +namespace std { + class type_info; +} + +namespace PR7114 { + class A { virtual ~A(); }; // expected-note{{declared private here}} + + template<typename T> + class B { + public: + class Inner : public A { }; // expected-error{{base class 'PR7114::A' has private destructor}} + static Inner i; + static const unsigned value = sizeof(i) == 4; + }; + + int f() { return B<int>::value; } + + void test_typeid(B<float>::Inner bfi) { + (void)typeid(bfi); // expected-note{{implicit default destructor}} + } + + template<typename T> + struct X : A { + void f() { } + }; + + void test_X(X<int> xi, X<float> xf) { + xi.f(); + } +} diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 494181675c5a..4268cec1b231 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -447,6 +447,31 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p, } /******************************************************************************/ +/* Typekind testing. */ +/******************************************************************************/ + +static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p, + CXClientData d) { + + if (!clang_isInvalid(clang_getCursorKind(cursor))) { + CXType T = clang_getCursorType(cursor); + CXType CT = clang_getCanonicalType(T); + CXString S = clang_getTypeKindSpelling(T.kind); + PrintCursor(cursor); + printf(" typekind=%s", clang_getCString(S)); + if (!clang_equalTypes(T, CT)) { + CXString CS = clang_getTypeKindSpelling(CT.kind); + printf(" [canonical=%s]", clang_getCString(CS)); + clang_disposeString(CS); + } + clang_disposeString(S); + printf("\n"); + } + return CXChildVisit_Recurse; +} + + +/******************************************************************************/ /* Loading ASTs/source. */ /******************************************************************************/ @@ -757,7 +782,8 @@ void print_completion_result(CXCompletionResult *completion_result, clang_disposeString(ks); print_completion_string(completion_result->CompletionString, file); - fprintf(file, "\n"); + fprintf(file, " (%u)\n", + clang_getCompletionPriority(completion_result->CompletionString)); } int perform_code_completion(int argc, const char **argv) { @@ -1179,6 +1205,7 @@ static void print_usage(void) { " c-index-test -test-inclusion-stack-source {<args>}*\n" " c-index-test -test-inclusion-stack-tu <AST file>\n" " c-index-test -test-print-linkage-source {<args>}*\n" + " c-index-test -test-print-typekind {<args>}*\n" " c-index-test -print-usr [<CursorKind> {<args>}]*\n" " c-index-test -print-usr-file <file>\n\n" " <symbol filter> values:\n%s", @@ -1223,6 +1250,9 @@ int main(int argc, const char **argv) { else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage, NULL); + else if (argc > 2 && strcmp(argv[1], "-test-print-typekind") == 0) + return perform_test_load_source(argc - 2, argv + 2, "all", + PrintTypeKind, 0); else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) { if (argc > 2) return print_usrs(argv + 2, argv + argc); diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index ca2f4081aa9f..706f05051c52 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -26,6 +26,7 @@ set( LLVM_LINK_COMPONENTS add_clang_executable(clang driver.cpp cc1_main.cpp + cc1as_main.cpp ) if(UNIX) diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index 144a734b151d..ac19e9393c5b 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -1,4 +1,4 @@ -//===-- cc1_main.cpp - Clang CC1 Driver -----------------------------------===// +//===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===// // // The LLVM Compiler Infrastructure // @@ -43,7 +43,7 @@ using namespace clang; // Main driver //===----------------------------------------------------------------------===// -void LLVMErrorHandler(void *UserData, const std::string &Message) { +static void LLVMErrorHandler(void *UserData, const std::string &Message) { Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); Diags.Report(diag::err_fe_error_backend) << Message; @@ -63,6 +63,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case ASTPrint: return new ASTPrintAction(); case ASTPrintXML: return new ASTPrintXMLAction(); case ASTView: return new ASTViewAction(); + case BoostCon: return new BoostConAction(); case DumpRawTokens: return new DumpRawTokensAction(); case DumpTokens: return new DumpTokensAction(); case EmitAssembly: return new EmitAssemblyAction(); @@ -70,6 +71,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case EmitHTML: return new HTMLPrintAction(); case EmitLLVM: return new EmitLLVMAction(); case EmitLLVMOnly: return new EmitLLVMOnlyAction(); + case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); case EmitObj: return new EmitObjAction(); case FixIt: return new FixItAction(); case GeneratePCH: return new GeneratePCHAction(); diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp new file mode 100644 index 000000000000..5f1ee092ba4f --- /dev/null +++ b/tools/driver/cc1as_main.cpp @@ -0,0 +1,373 @@ +//===-- cc1as_main.cpp - Clang Assembler ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the entry point to the clang -cc1as functionality, which implements +// the direct interface to the LLVM MC based assembler. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Driver/Arg.h" +#include "clang/Driver/ArgList.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/CC1AsOptions.h" +#include "clang/Driver/OptTable.h" +#include "clang/Driver/Options.h" +#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCParser/AsmParser.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" +#include "llvm/System/Signals.h" +#include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmParser.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetSelect.h" +using namespace clang; +using namespace clang::driver; +using namespace llvm; + +namespace { + +/// \brief Helper class for representing a single invocation of the assembler. +struct AssemblerInvocation { + /// @name Target Options + /// @{ + + std::string Triple; + + /// @} + /// @name Language Options + /// @{ + + std::vector<std::string> IncludePaths; + unsigned NoInitialTextSection : 1; + + /// @} + /// @name Frontend Options + /// @{ + + std::string InputFile; + std::vector<std::string> LLVMArgs; + std::string OutputPath; + enum FileType { + FT_Asm, ///< Assembly (.s) output, transliterate mode. + FT_Null, ///< No output, for timing purposes. + FT_Obj ///< Object file output. + }; + FileType OutputType; + unsigned ShowHelp : 1; + unsigned ShowVersion : 1; + + /// @} + /// @name Transliterate Options + /// @{ + + unsigned OutputAsmVariant; + unsigned ShowEncoding : 1; + unsigned ShowInst : 1; + + /// @} + /// @name Assembler Options + /// @{ + + unsigned RelaxAll : 1; + + /// @} + +public: + AssemblerInvocation() { + Triple = ""; + NoInitialTextSection = 0; + InputFile = "-"; + OutputPath = "-"; + OutputType = FT_Asm; + OutputAsmVariant = 0; + ShowInst = 0; + ShowEncoding = 0; + RelaxAll = 0; + } + + static void CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin, + const char **ArgEnd, Diagnostic &Diags); +}; + +} + +void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, + const char **ArgBegin, + const char **ArgEnd, + Diagnostic &Diags) { + using namespace clang::driver::cc1asoptions; + // Parse the arguments. + OwningPtr<OptTable> OptTbl(createCC1AsOptTable()); + unsigned MissingArgIndex, MissingArgCount; + OwningPtr<InputArgList> Args( + OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); + + // Check for missing argument error. + if (MissingArgCount) + Diags.Report(diag::err_drv_missing_argument) + << Args->getArgString(MissingArgIndex) << MissingArgCount; + + // Issue errors on unknown arguments. + for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN), + ie = Args->filtered_end(); it != ie; ++it) + Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args); + + // Construct the invocation. + + // Target Options + Opts.Triple = Args->getLastArgValue(OPT_triple); + if (Opts.Triple.empty()) // Use the host triple if unspecified. + Opts.Triple = sys::getHostTriple(); + + // Language Options + Opts.IncludePaths = Args->getAllArgValues(OPT_I); + Opts.NoInitialTextSection = Args->hasArg(OPT_n); + + // Frontend Options + if (Args->hasArg(OPT_INPUT)) { + bool First = true; + for (arg_iterator it = Args->filtered_begin(OPT_INPUT), + ie = Args->filtered_end(); it != ie; ++it, First=false) { + if (First) + Opts.InputFile = it->getValue(*Args); + else + Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args); + } + } + Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm); + Opts.OutputPath = Args->getLastArgValue(OPT_o); + if (Arg *A = Args->getLastArg(OPT_filetype)) { + StringRef Name = A->getValue(*Args); + unsigned OutputType = StringSwitch<unsigned>(Name) + .Case("asm", FT_Asm) + .Case("null", FT_Null) + .Case("obj", FT_Obj) + .Default(~0U); + if (OutputType == ~0U) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(*Args) << Name; + else + Opts.OutputType = FileType(OutputType); + } + Opts.ShowHelp = Args->hasArg(OPT_help); + Opts.ShowVersion = Args->hasArg(OPT_version); + + // Transliterate Options + Opts.OutputAsmVariant = Args->getLastArgIntValue(OPT_output_asm_variant, + 0, Diags); + Opts.ShowEncoding = Args->hasArg(OPT_show_encoding); + Opts.ShowInst = Args->hasArg(OPT_show_inst); + + // Assemble Options + Opts.RelaxAll = Args->hasArg(OPT_relax_all); +} + +static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts, + Diagnostic &Diags, + bool Binary) { + if (Opts.OutputPath.empty()) + Opts.OutputPath = "-"; + + // Make sure that the Out file gets unlinked from the disk if we get a + // SIGINT. + if (Opts.OutputPath != "-") + sys::RemoveFileOnSignal(sys::Path(Opts.OutputPath)); + + std::string Error; + raw_fd_ostream *Out = + new raw_fd_ostream(Opts.OutputPath.c_str(), Error, + (Binary ? raw_fd_ostream::F_Binary : 0)); + if (!Error.empty()) { + Diags.Report(diag::err_fe_unable_to_open_output) + << Opts.OutputPath << Error; + return 0; + } + + return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM); +} + +static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { + // Get the target specific parser. + std::string Error; + const Target *TheTarget(TargetRegistry::lookupTarget(Opts.Triple, Error)); + if (!TheTarget) { + Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; + return false; + } + + MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(Opts.InputFile, &Error); + if (Buffer == 0) { + Diags.Report(diag::err_fe_error_reading) << Opts.InputFile; + return false; + } + + SourceMgr SrcMgr; + + // Tell SrcMgr about this buffer, which is what the parser will pick up. + SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); + + // Record the location of the include directories so that the lexer can find + // it later. + SrcMgr.setIncludeDirs(Opts.IncludePaths); + + OwningPtr<MCAsmInfo> MAI(TheTarget->createAsmInfo(Opts.Triple)); + assert(MAI && "Unable to create target asm info!"); + + MCContext Ctx(*MAI); + bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; + formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary); + if (!Out) + return false; + + // FIXME: We shouldn't need to do this (and link in codegen). + OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple, "")); + if (!TM) { + Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; + return false; + } + + OwningPtr<MCCodeEmitter> CE; + OwningPtr<MCStreamer> Str; + OwningPtr<TargetAsmBackend> TAB; + + if (Opts.OutputType == AssemblerInvocation::FT_Asm) { + MCInstPrinter *IP = + TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI); + if (Opts.ShowEncoding) + CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); + Str.reset(createAsmStreamer(Ctx, *Out,TM->getTargetData()->isLittleEndian(), + /*asmverbose*/true, IP, CE.get(), + Opts.ShowInst)); + } else if (Opts.OutputType == AssemblerInvocation::FT_Null) { + Str.reset(createNullStreamer(Ctx)); + } else { + assert(Opts.OutputType == AssemblerInvocation::FT_Obj && + "Invalid file type!"); + CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); + TAB.reset(TheTarget->createAsmBackend(Opts.Triple)); + Str.reset(createMachOStreamer(Ctx, *TAB, *Out, CE.get(), Opts.RelaxAll)); + } + + AsmParser Parser(SrcMgr, Ctx, *Str.get(), *MAI); + OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(Parser)); + if (!TAP) { + Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; + return false; + } + + Parser.setTargetParser(*TAP.get()); + + bool Success = !Parser.Run(Opts.NoInitialTextSection); + + // Close the output. + delete Out; + + // Delete output on errors. + if (!Success && Opts.OutputPath != "-") + sys::Path(Opts.OutputPath).eraseFromDisk(); + + return Success; +} + +static void LLVMErrorHandler(void *UserData, const std::string &Message) { + Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); + + Diags.Report(diag::err_fe_error_backend) << Message; + + // We cannot recover from llvm errors. + exit(1); +} + +int cc1as_main(const char **ArgBegin, const char **ArgEnd, + const char *Argv0, void *MainAddr) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + // Initialize targets and assembly printers/parsers. + InitializeAllTargetInfos(); + // FIXME: We shouldn't need to initialize the Target(Machine)s. + InitializeAllTargets(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + // Construct our diagnostic client. + TextDiagnosticPrinter DiagClient(errs(), DiagnosticOptions()); + DiagClient.setPrefix("clang -cc1as"); + Diagnostic Diags(&DiagClient); + + // Set an error handler, so that any LLVM backend diagnostics go through our + // error handler. + install_fatal_error_handler(LLVMErrorHandler, + static_cast<void*>(&Diags)); + + // Parse the arguments. + AssemblerInvocation Asm; + AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags); + + // Honor -help. + if (Asm.ShowHelp) { + llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable()); + Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler"); + return 0; + } + + // Honor -version. + // + // FIXME: Use a better -version message? + if (Asm.ShowVersion) { + llvm::cl::PrintVersionMessage(); + return 0; + } + + // Honor -mllvm. + // + // FIXME: Remove this, one day. + if (!Asm.LLVMArgs.empty()) { + unsigned NumArgs = Asm.LLVMArgs.size(); + const char **Args = new const char*[NumArgs + 2]; + Args[0] = "clang (LLVM option parsing)"; + for (unsigned i = 0; i != NumArgs; ++i) + Args[i + 1] = Asm.LLVMArgs[i].c_str(); + Args[NumArgs + 1] = 0; + llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args)); + } + + // Execute the invocation, unless there were parsing errors. + bool Success = false; + if (!Diags.getNumErrors()) + Success = ExecuteAssembler(Asm, Diags); + + // If any timers were active but haven't been destroyed yet, print their + // results now. + TimerGroup::printAll(errs()); + + return !Success; +} diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 3f1cca1f887a..c4b12cba0f7a 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -170,15 +170,28 @@ static void ApplyQAOverride(std::vector<const char*> &Args, extern int cc1_main(const char **ArgBegin, const char **ArgEnd, const char *Argv0, void *MainAddr); +extern int cc1as_main(const char **ArgBegin, const char **ArgEnd, + const char *Argv0, void *MainAddr); int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc, argv); - // Dispatch to cc1_main if appropriate. - if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1") - return cc1_main(argv+2, argv+argc, argv[0], - (void*) (intptr_t) GetExecutablePath); + // Handle -cc1 integrated tools. + if (argc > 1 && llvm::StringRef(argv[1]).startswith("-cc1")) { + llvm::StringRef Tool = argv[1] + 4; + + if (Tool == "") + return cc1_main(argv+2, argv+argc, argv[0], + (void*) (intptr_t) GetExecutablePath); + if (Tool == "as") + return cc1as_main(argv+2, argv+argc, argv[0], + (void*) (intptr_t) GetExecutablePath); + + // Reject unknown tools. + llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n"; + return 1; + } bool CanonicalPrefixes = true; for (int i = 1; i < argc; ++i) { diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index f9f735113f7a..a077589c8f79 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -44,11 +44,11 @@ using namespace clang::cxstring; // Crash Reporting. //===----------------------------------------------------------------------===// -#ifdef __APPLE__ -#define USE_CRASHTRACER +#ifdef USE_CRASHTRACER #include "clang/Analysis/Support/SaveAndRestore.h" // Integrate with crash reporter. -extern "C" const char *__crashreporter_info__; +static const char *__crashreporter_info__ = 0; +asm(".desc ___crashreporter_info__, 0x10"); #define NUM_CRASH_STRINGS 32 static unsigned crashtracer_counter = 0; static unsigned crashtracer_counter_id[NUM_CRASH_STRINGS] = { 0 }; @@ -152,6 +152,23 @@ static RangeComparisonResult RangeCompare(SourceManager &SM, return RangeOverlap; } +/// \brief Determine if a source location falls within, before, or after a +/// a given source range. +static RangeComparisonResult LocationCompare(SourceManager &SM, + SourceLocation L, SourceRange R) { + assert(R.isValid() && "First range is invalid?"); + assert(L.isValid() && "Second range is invalid?"); + if (L == R.getBegin()) + return RangeOverlap; + if (L == R.getEnd()) + return RangeAfter; + if (SM.isBeforeInTranslationUnit(L, R.getBegin())) + return RangeBefore; + if (SM.isBeforeInTranslationUnit(R.getEnd(), L)) + return RangeAfter; + return RangeOverlap; +} + /// \brief Translate a Clang source range into a CIndex source range. /// /// Clang internally represents ranges where the end location points to the @@ -222,6 +239,27 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>, /// \param R a half-open source range retrieved from the abstract syntax tree. RangeComparisonResult CompareRegionOfInterest(SourceRange R); + class SetParentRAII { + CXCursor &Parent; + Decl *&StmtParent; + CXCursor OldParent; + + public: + SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent) + : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) + { + Parent = NewParent; + if (clang_isDeclaration(Parent.kind)) + StmtParent = getCursorDecl(Parent); + } + + ~SetParentRAII() { + Parent = OldParent; + if (clang_isDeclaration(Parent.kind)) + StmtParent = getCursorDecl(Parent); + } + }; + public: CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData, unsigned MaxPCHLevel, @@ -259,6 +297,7 @@ public: bool VisitObjCContainerDecl(ObjCContainerDecl *D); bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); + bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); bool VisitObjCImplDecl(ObjCImplDecl *D); bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); @@ -268,6 +307,8 @@ public: // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations. bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); bool VisitObjCClassDecl(ObjCClassDecl *D); + bool VisitLinkageSpecDecl(LinkageSpecDecl *D); + bool VisitNamespaceDecl(NamespaceDecl *D); // Type visitors // FIXME: QualifiedTypeLoc doesn't provide any location information @@ -277,6 +318,7 @@ public: bool VisitTagTypeLoc(TagTypeLoc TL); // FIXME: TemplateTypeParmTypeLoc doesn't provide any location information bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); + bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL); bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); bool VisitPointerTypeLoc(PointerTypeLoc TL); bool VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL); @@ -297,8 +339,10 @@ public: // FIXME: LabelStmt label? bool VisitIfStmt(IfStmt *S); bool VisitSwitchStmt(SwitchStmt *S); + bool VisitCaseStmt(CaseStmt *S); bool VisitWhileStmt(WhileStmt *S); bool VisitForStmt(ForStmt *S); +// bool VisitSwitchCase(SwitchCase *S); // Expression visitors bool VisitBlockExpr(BlockExpr *B); @@ -417,26 +461,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { // Set the Parent field to Cursor, then back to its old value once we're // done. - class SetParentRAII { - CXCursor &Parent; - Decl *&StmtParent; - CXCursor OldParent; - - public: - SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent) - : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) - { - Parent = NewParent; - if (clang_isDeclaration(Parent.kind)) - StmtParent = getCursorDecl(Parent); - } - - ~SetParentRAII() { - Parent = OldParent; - if (clang_isDeclaration(Parent.kind)) - StmtParent = getCursorDecl(Parent); - } - } SetParent(Parent, StmtParent, Cursor); + SetParentRAII SetParent(Parent, StmtParent, Cursor); if (clang_isDeclaration(Cursor.kind)) { Decl *D = getCursorDecl(Cursor); @@ -504,7 +529,11 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) { for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { - CXCursor Cursor = MakeCXCursor(*I, TU); + Decl *D = *I; + if (D->getLexicalDeclContext() != DC) + continue; + + CXCursor Cursor = MakeCXCursor(D, TU); if (RegionOfInterest.isValid()) { SourceRange Range = @@ -642,6 +671,40 @@ bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { return VisitObjCContainerDecl(PID); } +bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) { + // FIXME: This implements a workaround with @property declarations also being + // installed in the DeclContext for the @interface. Eventually this code + // should be removed. + ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(PD->getDeclContext()); + if (!CDecl || !CDecl->IsClassExtension()) + return false; + + ObjCInterfaceDecl *ID = CDecl->getClassInterface(); + if (!ID) + return false; + + IdentifierInfo *PropertyId = PD->getIdentifier(); + ObjCPropertyDecl *prevDecl = + ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(ID), PropertyId); + + if (!prevDecl) + return false; + + // Visit synthesized methods since they will be skipped when visiting + // the @interface. + if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl()) + if (MD->isSynthesized()) + if (Visit(MakeCXCursor(MD, TU))) + return true; + + if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl()) + if (MD->isSynthesized()) + if (Visit(MakeCXCursor(MD, TU))) + return true; + + return false; +} + bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // Issue callbacks for super class. if (D->getSuperClass() && @@ -705,6 +768,14 @@ bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) { return false; } +bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + return VisitDeclContext(D); +} + bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { ASTContext &Context = TU->getASTContext(); @@ -780,6 +851,13 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) return true; + return false; +} + +bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc())) + return true; + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), TU))) @@ -790,19 +868,7 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseTypeLoc())) - return true; - - if (TL.hasProtocolsAsWritten()) { - for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { - if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), - TL.getProtocolLoc(I), - TU))) - return true; - } - } - - return false; + return Visit(TL.getPointeeLoc()); } bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) { @@ -861,13 +927,60 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { bool CursorVisitor::VisitStmt(Stmt *S) { for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end(); Child != ChildEnd; ++Child) { - if (*Child && Visit(MakeCXCursor(*Child, StmtParent, TU))) - return true; + if (Stmt *C = *Child) + if (Visit(MakeCXCursor(C, StmtParent, TU))) + return true; } return false; } +bool CursorVisitor::VisitCaseStmt(CaseStmt *S) { + // Specially handle CaseStmts because they can be nested, e.g.: + // + // case 1: + // case 2: + // + // In this case the second CaseStmt is the child of the first. Walking + // these recursively can blow out the stack. + CXCursor Cursor = MakeCXCursor(S, StmtParent, TU); + while (true) { + // Set the Parent field to Cursor, then back to its old value once we're + // done. + SetParentRAII SetParent(Parent, StmtParent, Cursor); + + if (Stmt *LHS = S->getLHS()) + if (Visit(MakeCXCursor(LHS, StmtParent, TU))) + return true; + if (Stmt *RHS = S->getRHS()) + if (Visit(MakeCXCursor(RHS, StmtParent, TU))) + return true; + if (Stmt *SubStmt = S->getSubStmt()) { + if (!isa<CaseStmt>(SubStmt)) + return Visit(MakeCXCursor(SubStmt, StmtParent, TU)); + + // Specially handle 'CaseStmt' so that we don't blow out the stack. + CaseStmt *CS = cast<CaseStmt>(SubStmt); + Cursor = MakeCXCursor(CS, StmtParent, TU); + if (RegionOfInterest.isValid()) { + SourceRange Range = CS->getSourceRange(); + if (Range.isInvalid() || CompareRegionOfInterest(Range)) + return false; + } + + switch (Visitor(Cursor, Parent, ClientData)) { + case CXChildVisit_Break: return true; + case CXChildVisit_Continue: return false; + case CXChildVisit_Recurse: + // Perform tail-recursion manually. + S = CS; + continue; + } + } + return false; + } +} + bool CursorVisitor::VisitDeclStmt(DeclStmt *S) { for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); D != DEnd; ++D) { @@ -1089,8 +1202,6 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, RemappedFiles.size(), /*CaptureDiagnostics=*/true)); - // FIXME: Until we have broader testing, just drop the entire AST if we - // encountered an error. if (NumErrors != Diags->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. if (CXXIdx->getDisplayDiagnostics() && Unit.get()) { @@ -1368,6 +1479,16 @@ CXSourceLocation clang_getRangeEnd(CXSourceRange range) { return Result; } +unsigned clang_isFromMainFile(CXSourceLocation loc) { + SourceLocation Loc = SourceLocation::getFromRawEncoding(loc.int_data); + if (!loc.ptr_data[0] || Loc.isInvalid()) + return 0; + + const SourceManager &SM = + *static_cast<const SourceManager*>(loc.ptr_data[0]); + return SM.isFromMainFile(Loc) ? 1 : 0; +} + } // end: extern "C" //===----------------------------------------------------------------------===// @@ -1474,10 +1595,11 @@ static CXString getDeclSpelling(Decl *D) { // ObjCCategoryImplDecl returns the category name. return createCXString(CIMP->getIdentifier()->getNameStart()); - if (ND->getIdentifier()) - return createCXString(ND->getIdentifier()->getNameStart()); - - return createCXString(""); + llvm::SmallString<1024> S; + llvm::raw_svector_ostream os(S); + ND->printName(os); + + return createCXString(os.str()); } CXString clang_getCursorSpelling(CXCursor C) { @@ -1615,12 +1737,18 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("attribute(ibaction)"); case CXCursor_IBOutletAttr: return createCXString("attribute(iboutlet)"); + case CXCursor_IBOutletCollectionAttr: + return createCXString("attribute(iboutletcollection)"); case CXCursor_PreprocessingDirective: return createCXString("preprocessing directive"); case CXCursor_MacroDefinition: return createCXString("macro definition"); case CXCursor_MacroInstantiation: return createCXString("macro instantiation"); + case CXCursor_Namespace: + return createCXString("Namespace"); + case CXCursor_LinkageSpec: + return createCXString("LinkageSpec"); } llvm_unreachable("Unhandled CXCursorKind"); @@ -1763,7 +1891,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(getCursorContext(C), L); } - if (!getCursorDecl(C)) + if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) return clang_getNullLocation(); Decl *D = getCursorDecl(C); @@ -1829,7 +1957,7 @@ CXSourceRange clang_getCursorExtent(CXCursor C) { return cxloc::translateSourceRange(getCursorContext(C), R); } - if (!getCursorDecl(C)) + if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) return clang_getNullRange(); Decl *D = getCursorDecl(C); @@ -2286,9 +2414,15 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, const char *StartPos = Buf.data() + LocInfo.second; IdentifierInfo *II = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos); - CXTok.int_data[0] = II->getTokenID() == tok::identifier? - CXToken_Identifier - : CXToken_Keyword; + + if (II->getObjCKeywordID() != tok::objc_not_keyword) { + CXTok.int_data[0] = CXToken_Keyword; + } + else { + CXTok.int_data[0] = II->getTokenID() == tok::identifier? + CXToken_Identifier + : CXToken_Keyword; + } CXTok.ptr_data = II; } else if (Tok.is(tok::comment)) { CXTok.int_data[0] = CXToken_Comment; @@ -2308,62 +2442,214 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, *NumTokens = CXTokens.size(); } +void clang_disposeTokens(CXTranslationUnit TU, + CXToken *Tokens, unsigned NumTokens) { + free(Tokens); +} + +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// Token annotation APIs. +//===----------------------------------------------------------------------===// + typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData; +static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data); +namespace { +class AnnotateTokensWorker { + AnnotateTokensData &Annotated; + CXToken *Tokens; + CXCursor *Cursors; + unsigned NumTokens; + unsigned TokIdx; + CursorVisitor AnnotateVis; + SourceManager &SrcMgr; + + bool MoreTokens() const { return TokIdx < NumTokens; } + unsigned NextToken() const { return TokIdx; } + void AdvanceToken() { ++TokIdx; } + SourceLocation GetTokenLoc(unsigned tokI) { + return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]); + } -enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, - CXCursor parent, - CXClientData client_data) { - AnnotateTokensData *Data = static_cast<AnnotateTokensData *>(client_data); - - // We only annotate the locations of declarations, simple - // references, and expressions which directly reference something. - CXCursorKind Kind = clang_getCursorKind(cursor); - if (clang_isDeclaration(Kind) || clang_isReference(Kind)) { - // Okay: We can annotate the location of this declaration with the - // declaration or reference - } else if (clang_isExpression(cursor.kind)) { - if (Kind != CXCursor_DeclRefExpr && - Kind != CXCursor_MemberRefExpr && - Kind != CXCursor_ObjCMessageExpr) - return CXChildVisit_Recurse; - - CXCursor Referenced = clang_getCursorReferenced(cursor); - if (Referenced == cursor || Referenced == clang_getNullCursor()) - return CXChildVisit_Recurse; - - // Okay: we can annotate the location of this expression - } else if (clang_isPreprocessing(cursor.kind)) { - // We can always annotate a preprocessing directive/macro instantiation. - } else { - // Nothing to annotate - return CXChildVisit_Recurse; +public: + AnnotateTokensWorker(AnnotateTokensData &annotated, + CXToken *tokens, CXCursor *cursors, unsigned numTokens, + ASTUnit *CXXUnit, SourceRange RegionOfInterest) + : Annotated(annotated), Tokens(tokens), Cursors(cursors), + NumTokens(numTokens), TokIdx(0), + AnnotateVis(CXXUnit, AnnotateTokensVisitor, this, + Decl::MaxPCHLevel, RegionOfInterest), + SrcMgr(CXXUnit->getSourceManager()) {} + + void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); } + enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent); + void AnnotateTokens(CXCursor parent); +}; +} + +void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) { + // Walk the AST within the region of interest, annotating tokens + // along the way. + VisitChildren(parent); + + for (unsigned I = 0 ; I < TokIdx ; ++I) { + AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); + if (Pos != Annotated.end()) + Cursors[I] = Pos->second; } + // Finish up annotating any tokens left. + if (!MoreTokens()) + return; + + const CXCursor &C = clang_getNullCursor(); + for (unsigned I = TokIdx ; I < NumTokens ; ++I) { + AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); + Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second; + } +} + +enum CXChildVisitResult +AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { CXSourceLocation Loc = clang_getCursorLocation(cursor); - (*Data)[Loc.int_data] = cursor; - return CXChildVisit_Recurse; + // We can always annotate a preprocessing directive/macro instantiation. + if (clang_isPreprocessing(cursor.kind)) { + Annotated[Loc.int_data] = cursor; + return CXChildVisit_Recurse; + } + + CXSourceRange cursorExtent = clang_getCursorExtent(cursor); + SourceRange cursorRange = cxloc::translateCXSourceRange(cursorExtent); + + if (cursorRange.isInvalid()) + return CXChildVisit_Continue; + + SourceLocation L = SourceLocation::getFromRawEncoding(Loc.int_data); + + // Adjust the annotated range based specific declarations. + const enum CXCursorKind cursorK = clang_getCursorKind(cursor); + if (cursorK >= CXCursor_FirstDecl && cursorK <= CXCursor_LastDecl) { + Decl *D = cxcursor::getCursorDecl(cursor); + // Don't visit synthesized ObjC methods, since they have no syntatic + // representation in the source. + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->isSynthesized()) + return CXChildVisit_Continue; + } + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { + if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) { + TypeLoc TL = TI->getTypeLoc(); + SourceLocation TLoc = TL.getSourceRange().getBegin(); + if (TLoc.isValid() && + SrcMgr.isBeforeInTranslationUnit(TLoc, L)) + cursorRange.setBegin(TLoc); + } + } + } + + const enum CXCursorKind K = clang_getCursorKind(parent); + const CXCursor updateC = + (clang_isInvalid(K) || K == CXCursor_TranslationUnit || + L.isMacroID()) + ? clang_getNullCursor() : parent; + + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + Cursors[I] = updateC; + AdvanceToken(); + continue; + case RangeAfter: + return CXChildVisit_Continue; + case RangeOverlap: + break; + } + break; + } + + // Visit children to get their cursor information. + const unsigned BeforeChildren = NextToken(); + VisitChildren(cursor); + const unsigned AfterChildren = NextToken(); + + // Adjust 'Last' to the last token within the extent of the cursor. + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + assert(0 && "Infeasible"); + case RangeAfter: + break; + case RangeOverlap: + Cursors[I] = updateC; + AdvanceToken(); + continue; + } + break; + } + const unsigned Last = NextToken(); + + // Scan the tokens that are at the beginning of the cursor, but are not + // capture by the child cursors. + + // For AST elements within macros, rely on a post-annotate pass to + // to correctly annotate the tokens with cursors. Otherwise we can + // get confusing results of having tokens that map to cursors that really + // are expanded by an instantiation. + if (L.isMacroID()) + cursor = clang_getNullCursor(); + + for (unsigned I = BeforeChildren; I != AfterChildren; ++I) { + if (!clang_isInvalid(clang_getCursorKind(Cursors[I]))) + break; + Cursors[I] = cursor; + } + // Scan the tokens that are at the end of the cursor, but are not captured + // but the child cursors. + for (unsigned I = AfterChildren; I != Last; ++I) + Cursors[I] = cursor; + + TokIdx = Last; + return CXChildVisit_Continue; } +static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent); +} + +extern "C" { + void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens, unsigned NumTokens, CXCursor *Cursors) { - if (NumTokens == 0) - return; - // Any token we don't specifically annotate will have a NULL cursor. - for (unsigned I = 0; I != NumTokens; ++I) - Cursors[I] = clang_getNullCursor(); + if (NumTokens == 0 || !Tokens || !Cursors) + return; ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU); - if (!CXXUnit || !Tokens) + if (!CXXUnit) { + // Any token we don't specifically annotate will have a NULL cursor. + const CXCursor &C = clang_getNullCursor(); + for (unsigned I = 0; I != NumTokens; ++I) + Cursors[I] = C; return; + } ASTUnit::ConcurrencyCheck Check(*CXXUnit); // Determine the region of interest, which contains all of the tokens. SourceRange RegionOfInterest; - RegionOfInterest.setBegin( - cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0]))); + RegionOfInterest.setBegin(cxloc::translateSourceLocation( + clang_getTokenLocation(TU, Tokens[0]))); + SourceLocation End = cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[NumTokens - 1])); @@ -2373,14 +2659,14 @@ void clang_annotateTokens(CXTranslationUnit TU, // region of interest to the corresponding cursors. AnnotateTokensData Annotated; - // Relex the tokens within the source range to look for preprocessing + // Relex the tokens within the source range to look for preprocessing // directives. SourceManager &SourceMgr = CXXUnit->getSourceManager(); std::pair<FileID, unsigned> BeginLocInfo = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin()); std::pair<FileID, unsigned> EndLocInfo = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd()); - + llvm::StringRef Buffer; bool Invalid = false; if (BeginLocInfo.first == EndLocInfo.first && @@ -2388,16 +2674,16 @@ void clang_annotateTokens(CXTranslationUnit TU, !Invalid) { Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), CXXUnit->getASTContext().getLangOptions(), - Buffer.begin(), Buffer.data() + BeginLocInfo.second, + Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end()); Lex.SetCommentRetentionState(true); - - // Lex tokens in raw mode until we hit the end of the range, to avoid + + // Lex tokens in raw mode until we hit the end of the range, to avoid // entering #includes or expanding macros. while (true) { Token Tok; Lex.LexFromRawLexer(Tok); - + reprocess: if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { // We have found a preprocessing directive. Gobble it up so that we @@ -2410,51 +2696,35 @@ void clang_annotateTokens(CXTranslationUnit TU, std::vector<SourceLocation> Locations; do { Locations.push_back(Tok.getLocation()); - Lex.LexFromRawLexer(Tok); + Lex.LexFromRawLexer(Tok); } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof)); - + using namespace cxcursor; CXCursor Cursor = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(), Locations.back()), - CXXUnit); + CXXUnit); for (unsigned I = 0, N = Locations.size(); I != N; ++I) { Annotated[Locations[I].getRawEncoding()] = Cursor; } - + if (Tok.isAtStartOfLine()) goto reprocess; - + continue; } - + if (Tok.is(tok::eof)) break; } } - - // Annotate all of the source locations in the region of interest that map to - // a specific cursor. - CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit); - CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated, - Decl::MaxPCHLevel, RegionOfInterest); - AnnotateVis.VisitChildren(Parent); - - for (unsigned I = 0; I != NumTokens; ++I) { - // Determine whether we saw a cursor at this token's location. - AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); - if (Pos == Annotated.end()) - continue; - - Cursors[I] = Pos->second; - } -} -void clang_disposeTokens(CXTranslationUnit TU, - CXToken *Tokens, unsigned NumTokens) { - free(Tokens); + // Annotate all of the source locations in the region of interest that map to + // a specific cursor. + AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens, + CXXUnit, RegionOfInterest); + W.AnnotateTokens(clang_getTranslationUnitCursor(CXXUnit)); } - } // end: extern "C" //===----------------------------------------------------------------------===// @@ -2540,6 +2810,21 @@ CXLanguageKind clang_getCursorLanguage(CXCursor cursor) { } } // end: extern "C" + +//===----------------------------------------------------------------------===// +// C++ AST instrospection. +//===----------------------------------------------------------------------===// + +extern "C" { +unsigned clang_CXXMethod_isStatic(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + CXXMethodDecl *D = dyn_cast<CXXMethodDecl>(cxcursor::getCursorDecl(C)); + return (D && D->isStatic()) ? 1 : 0; +} + +} // end: extern "C" + //===----------------------------------------------------------------------===// // CXString Operations. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index a21614c74735..481a375fb839 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -37,12 +37,27 @@ using namespace clang; using namespace clang::cxstring; +namespace { + /// \brief Stored representation of a completion string. + /// + /// This is the representation behind a CXCompletionString. + class CXStoredCodeCompletionString : public CodeCompletionString { + unsigned Priority; + + public: + CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { } + + unsigned getPriority() const { return Priority; } + }; +} + extern "C" { enum CXCompletionChunkKind clang_getCompletionChunkKind(CXCompletionString completion_string, unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return CXCompletionChunk_Text; @@ -97,7 +112,8 @@ clang_getCompletionChunkKind(CXCompletionString completion_string, CXString clang_getCompletionChunkText(CXCompletionString completion_string, unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return createCXString(0); @@ -121,9 +137,12 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string, case CodeCompletionString::CK_SemiColon: case CodeCompletionString::CK_Equal: case CodeCompletionString::CK_HorizontalSpace: - case CodeCompletionString::CK_VerticalSpace: return createCXString((*CCStr)[chunk_number].Text, false); + case CodeCompletionString::CK_VerticalSpace: + // FIXME: Temporary hack until we figure out how to handle vertical space. + return createCXString(" "); + case CodeCompletionString::CK_Optional: // Note: treated as an empty text block. return createCXString(""); @@ -137,7 +156,8 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string, CXCompletionString clang_getCompletionChunkCompletionString(CXCompletionString completion_string, unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return 0; @@ -174,10 +194,17 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string, } unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; return CCStr? CCStr->size() : 0; } +unsigned clang_getCompletionPriority(CXCompletionString completion_string) { + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; + return CCStr? CCStr->getPriority() : CCP_Unlikely; +} + static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, unsigned &Value) { if (Memory + sizeof(unsigned) > MemoryEnd) @@ -223,7 +250,7 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { for (unsigned I = 0, N = NumResults; I != N; ++I) - delete (CodeCompletionString *)Results[I].CompletionString; + delete (CXStoredCodeCompletionString *)Results[I].CompletionString; delete [] Results; delete Buffer; @@ -373,10 +400,16 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, if (ReadUnsigned(Str, StrEnd, KindValue)) break; - CodeCompletionString *CCStr - = CodeCompletionString::Deserialize(Str, StrEnd); - if (!CCStr) + unsigned Priority; + if (ReadUnsigned(Str, StrEnd, Priority)) + break; + + CXStoredCodeCompletionString *CCStr + = new CXStoredCodeCompletionString(Priority); + if (!CCStr->Deserialize(Str, StrEnd)) { + delete CCStr; continue; + } if (!CCStr->empty()) { // Vend the code-completion result to the caller. diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index f3c74e85316f..e98fd262a712 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -28,12 +28,33 @@ using namespace clang::cxstring; namespace { class USRGenerator : public DeclVisitor<USRGenerator> { - llvm::raw_ostream &Out; + llvm::SmallString<1024> Buf; + llvm::raw_svector_ostream Out; bool IgnoreResults; ASTUnit *AU; + bool generatedLoc; public: - USRGenerator(ASTUnit *au, llvm::raw_ostream &out) - : Out(out), IgnoreResults(false), AU(au) {} + USRGenerator(const CXCursor *C = 0) + : Out(Buf), + IgnoreResults(false), + AU(C ? cxcursor::getCursorASTUnit(*C) : 0), + generatedLoc(false) + { + // Add the USR space prefix. + Out << "c:"; + } + + llvm::StringRef str() { + return Out.str(); + } + + USRGenerator* operator->() { return this; } + + template <typename T> + llvm::raw_svector_ostream &operator<<(const T &x) { + Out << x; + return Out; + } bool ignoreResults() const { return IgnoreResults; } @@ -52,10 +73,14 @@ public: void VisitTagDecl(TagDecl *D); void VisitTypedefDecl(TypedefDecl *D); void VisitVarDecl(VarDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D) { + IgnoreResults = true; + return; + } /// Generate the string component containing the location of the /// declaration. - void GenLoc(const Decl *D); + bool GenLoc(const Decl *D); /// String generation methods used both by the visitation methods /// and from other clients that want to directly generate USRs. These @@ -63,10 +88,6 @@ public: /// 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. @@ -81,31 +102,12 @@ public: 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(const CXCursor *C = 0) - : Out(StrBuf), UG(C ? cxcursor::getCursorASTUnit(*C) : 0, Out) { - // Add the USR space prefix. - Out << "c:"; - } - - llvm::StringRef str() { - return Out.str(); - } + void VisitType(QualType T); - USRGenerator* operator->() { return &UG; } - - template <typename T> - llvm::raw_svector_ostream &operator<<(const T &x) { - Out << x; - return Out; - } + /// Emit a Decl's name using NamedDecl::printName() and return true if + /// the decl had no name. + bool EmitDeclName(const NamedDecl *D); }; } // end anonymous namespace @@ -114,56 +116,91 @@ public: // Generating USRs from ASTS. //===----------------------------------------------------------------------===// +bool USRGenerator::EmitDeclName(const NamedDecl *D) { + Out.flush(); + const unsigned startSize = Buf.size(); + D->printName(Out); + Out.flush(); + const unsigned endSize = Buf.size(); + return startSize == endSize; +} + +static bool InAnonymousNamespace(const Decl *D) { + if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext())) + return ND->isAnonymousNamespace(); + return false; +} + +static inline bool ShouldGenerateLocation(const NamedDecl *D) { + return D->getLinkage() != ExternalLinkage && !InAnonymousNamespace(D); +} + void USRGenerator::VisitDeclContext(DeclContext *DC) { if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) Visit(D); } void USRGenerator::VisitFieldDecl(FieldDecl *D) { - const std::string &s = D->getNameAsString(); - if (s.empty()) { + VisitDeclContext(D->getDeclContext()); + Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@"); + if (EmitDeclName(D)) { // Bit fields can be anonymous. IgnoreResults = true; return; } - VisitDeclContext(D->getDeclContext()); - Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@") << s; } void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { - if (D->getLinkage() != ExternalLinkage) { - GenLoc(D); - if (IgnoreResults) - return; - } - else - VisitDeclContext(D->getDeclContext()); + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); + Out << "@F@"; + D->printName(Out); + + ASTContext &Ctx = AU->getASTContext(); + if (!Ctx.getLangOptions().CPlusPlus || D->isExternC()) + return; - Out << "@F@" << D; + // Mangle in type information for the arguments. + for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); + I != E; ++I) { + Out << '#'; + if (ParmVarDecl *PD = *I) + VisitType(PD->getType()); + } + if (D->isVariadic()) + Out << '.'; + Out << '#'; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + if (MD->isStatic()) + Out << 'S'; + if (unsigned quals = MD->getTypeQualifiers()) + Out << (char)('0' + quals); + } } void USRGenerator::VisitNamedDecl(NamedDecl *D) { VisitDeclContext(D->getDeclContext()); - const std::string &s = D->getNameAsString(); - // The string can be empty if the declaration has no name; e.g., it is - // the ParmDecl with no name for declaration of a function pointer type, e.g.: - // void (*f)(void *); - // In this case, don't generate a USR. - if (s.empty()) + Out << "@"; + + if (EmitDeclName(D)) { + // The string can be empty if the declaration has no name; e.g., it is + // the ParmDecl with no name for declaration of a function pointer type, + // e.g.: void (*f)(void *); + // In this case, don't generate a USR. IgnoreResults = true; - else - GenNamedDecl(s); + } } void USRGenerator::VisitVarDecl(VarDecl *D) { // VarDecls can be declared 'extern' within a function or method body, // but their enclosing DeclContext is the function, not the TU. We need // to check the storage class to correctly generate the USR. - if (D->getLinkage() != ExternalLinkage) { - GenLoc(D); - if (IgnoreResults) - return; - } + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); // Variables always have simple names. llvm::StringRef s = D->getName(); @@ -175,18 +212,28 @@ void USRGenerator::VisitVarDecl(VarDecl *D) { if (s.empty()) IgnoreResults = true; else - GenNamedDecl(s); + Out << '@' << s; } void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { + if (D->isAnonymousNamespace()) { + Out << "@aN"; + return; + } + VisitDeclContext(D->getDeclContext()); - Out << "@N@" << D; + if (!IgnoreResults) + Out << "@N@" << D->getName(); } void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { Visit(cast<Decl>(D->getDeclContext())); - GenObjCMethod(DeclarationName(D->getSelector()).getAsString(), - D->isInstanceMethod()); + // Ideally we would use 'GenObjCMethod', but this is such a hot path + // for Objective-C code that we don't want to use + // DeclarationName::getAsString(). + Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); + DeclarationName N(D->getSelector()); + N.printName(Out); } void USRGenerator::VisitObjCClassDecl(ObjCClassDecl *D) { @@ -258,59 +305,56 @@ void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { } void USRGenerator::VisitTagDecl(TagDecl *D) { + // Add the location of the tag decl to handle resolution across + // translation units. + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + D = D->getCanonicalDecl(); VisitDeclContext(D->getDeclContext()); - switch (D->getTagKind()) { - case TagDecl::TK_struct: Out << "@S"; break; - case TagDecl::TK_class: Out << "@C"; break; - case TagDecl::TK_union: Out << "@U"; break; - case TagDecl::TK_enum: Out << "@E"; break; - } - const std::string &s = D->getNameAsString(); - const TypedefDecl *TD = 0; - if (s.empty()) { - TD = D->getTypedefForAnonDecl(); - Out << (TD ? 'A' : 'a'); + switch (D->getTagKind()) { + case TTK_Struct: Out << "@S"; break; + case TTK_Class: Out << "@C"; break; + case TTK_Union: Out << "@U"; break; + case TTK_Enum: Out << "@E"; break; } - // Add the location of the tag decl to handle resolution across - // translation units. - if (D->getLinkage() == NoLinkage) { - Out << '@'; - GenLoc(D); - if (IgnoreResults) - return; - } + Out << '@'; + Out.flush(); + assert(Buf.size() > 0); + const unsigned off = Buf.size() - 1; - if (s.empty()) { - if (TD) + if (EmitDeclName(D)) { + if (const TypedefDecl *TD = D->getTypedefForAnonDecl()) { + Buf[off] = 'A'; Out << '@' << TD; + } + else + Buf[off] = 'a'; } - else - Out << '@' << s; } void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; DeclContext *DC = D->getDeclContext(); if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC)) Visit(DCN); Out << "@T@"; - if (D->getLinkage() == NoLinkage) { - GenLoc(D); - if (IgnoreResults) - return; - Out << '@'; - } Out << D->getName(); } -void USRGenerator::GenLoc(const Decl *D) { +bool USRGenerator::GenLoc(const Decl *D) { + if (generatedLoc) + return IgnoreResults; + generatedLoc = true; + const SourceManager &SM = AU->getSourceManager(); SourceLocation L = D->getLocStart(); if (L.isInvalid()) { IgnoreResults = true; - return; + return true; } L = SM.getInstantiationLoc(L); const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L); @@ -322,21 +366,145 @@ void USRGenerator::GenLoc(const Decl *D) { else { // This case really isn't interesting. IgnoreResults = true; - return; + return true; } Out << '@' << SM.getLineNumber(Decomposed.first, Decomposed.second) << ':' << SM.getColumnNumber(Decomposed.first, Decomposed.second); + + return IgnoreResults; +} + +void USRGenerator::VisitType(QualType T) { + // This method mangles in USR information for types. It can possibly + // just reuse the naming-mangling logic used by codegen, although the + // requirements for USRs might not be the same. + ASTContext &Ctx = AU->getASTContext(); + + do { + T = Ctx.getCanonicalType(T); + Qualifiers Q = T.getQualifiers(); + unsigned qVal = 0; + if (Q.hasConst()) + qVal |= 0x1; + if (Q.hasVolatile()) + qVal |= 0x2; + if (Q.hasRestrict()) + qVal |= 0x4; + if(qVal) + Out << ((char) ('0' + qVal)); + + // Mangle in ObjC GC qualifiers? + + if (const PointerType *PT = T->getAs<PointerType>()) { + Out << '*'; + T = PT->getPointeeType(); + continue; + } + if (const ReferenceType *RT = T->getAs<ReferenceType>()) { + Out << '&'; + T = RT->getPointeeType(); + continue; + } + if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) { + Out << 'F'; + VisitType(FT->getResultType()); + for (FunctionProtoType::arg_type_iterator + I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) { + VisitType(*I); + } + if (FT->isVariadic()) + Out << '.'; + return; + } + if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) { + Out << 'B'; + T = BT->getPointeeType(); + continue; + } + if (const BuiltinType *BT = T->getAs<BuiltinType>()) { + unsigned char c = '\0'; + switch (BT->getKind()) { + case BuiltinType::Void: + c = 'v'; break; + case BuiltinType::Bool: + c = 'b'; break; + case BuiltinType::Char_U: + case BuiltinType::UChar: + c = 'c'; break; + case BuiltinType::Char16: + c = 'q'; break; + case BuiltinType::Char32: + c = 'w'; break; + case BuiltinType::UShort: + c = 's'; break; + case BuiltinType::UInt: + c = 'i'; break; + case BuiltinType::ULong: + c = 'l'; break; + case BuiltinType::ULongLong: + c = 'k'; break; + case BuiltinType::UInt128: + c = 'j'; break; + case BuiltinType::Char_S: + case BuiltinType::SChar: + c = 'C'; break; + case BuiltinType::WChar: + c = 'W'; break; + case BuiltinType::Short: + c = 'S'; break; + case BuiltinType::Int: + c = 'I'; break; + case BuiltinType::Long: + c = 'L'; break; + case BuiltinType::LongLong: + c = 'K'; break; + case BuiltinType::Int128: + c = 'J'; break; + case BuiltinType::Float: + c = 'f'; break; + case BuiltinType::Double: + c = 'd'; break; + case BuiltinType::LongDouble: + c = 'D'; break; + case BuiltinType::NullPtr: + c = 'n'; break; + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::UndeducedAuto: + IgnoreResults = true; + return; + case BuiltinType::ObjCId: + c = 'o'; break; + case BuiltinType::ObjCClass: + c = 'O'; break; + case BuiltinType::ObjCSel: + c = 'e'; break; + } + Out << c; + return; + } + if (const ComplexType *CT = T->getAs<ComplexType>()) { + Out << '<'; + T = CT->getElementType(); + continue; + } + if (const TagType *TT = T->getAs<TagType>()) { + Out << '$'; + VisitTagDecl(TT->getDecl()); + return; + } + + // Unhandled type. + Out << ' '; + break; + } while (true); } //===----------------------------------------------------------------------===// // General purpose USR generation methods. //===----------------------------------------------------------------------===// -void USRGenerator::GenNamedDecl(llvm::StringRef name) { - Out << "@" << name; -} - void USRGenerator::GenObjCClass(llvm::StringRef cls) { Out << "objc(cs)" << cls; } @@ -346,7 +514,7 @@ void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) { } void USRGenerator::GenObjCIvar(llvm::StringRef ivar) { - GenNamedDecl(ivar); + Out << '@' << ivar; } void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) { @@ -383,6 +551,7 @@ static CXString getDeclCursorUSR(const CXCursor &C) { // Generate USRs for all entities with external linkage. break; case NoLinkage: + case UniqueExternalLinkage: // We allow enums, typedefs, and structs that have no linkage to // have USRs that are anchored to the file they were defined in // (e.g., the header). This is a little gross, but in principal @@ -390,27 +559,27 @@ static CXString getDeclCursorUSR(const CXCursor &C) { // are referred to across multiple translation units. if (isa<TagDecl>(ND) || isa<TypedefDecl>(ND) || isa<EnumConstantDecl>(ND) || isa<FieldDecl>(ND) || - isa<VarDecl>(ND)) + isa<VarDecl>(ND) || isa<NamespaceDecl>(ND)) break; // Fall-through. case InternalLinkage: if (isa<FunctionDecl>(ND)) break; - case UniqueExternalLinkage: - return createCXString(""); } - StringUSRGenerator SUG(&C); - SUG->Visit(D); + USRGenerator UG(&C); + UG->Visit(D); - if (SUG->ignoreResults()) + if (UG->ignoreResults()) return createCXString(""); +#if 0 // For development testing. - // assert(SUG.str().size() > 2); + assert(UG.str().size() > 2); +#endif // Return a copy of the string that must be disposed by the caller. - return createCXString(SUG.str(), true); + return createCXString(UG.str(), true); } extern "C" { @@ -422,56 +591,56 @@ CXString clang_getCursorUSR(CXCursor C) { return getDeclCursorUSR(C); if (K == CXCursor_MacroDefinition) { - StringUSRGenerator SUG(&C); - SUG << "macro@" - << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); - return createCXString(SUG.str(), true); + USRGenerator UG(&C); + UG << "macro@" + << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); + return createCXString(UG.str(), true); } return createCXString(""); } CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) { - StringUSRGenerator SUG; - SUG << extractUSRSuffix(clang_getCString(classUSR)); - SUG->GenObjCIvar(name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCIvar(name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCMethod(const char *name, unsigned isInstanceMethod, CXString classUSR) { - StringUSRGenerator SUG; - SUG << extractUSRSuffix(clang_getCString(classUSR)); - SUG->GenObjCMethod(name, isInstanceMethod); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCMethod(name, isInstanceMethod); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCClass(const char *name) { - StringUSRGenerator SUG; - SUG->GenObjCClass(name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG->GenObjCClass(name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCProtocol(const char *name) { - StringUSRGenerator SUG; - SUG->GenObjCProtocol(name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG->GenObjCProtocol(name); + return createCXString(UG.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); + USRGenerator UG; + UG->GenObjCCategory(class_name, category_name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCProperty(const char *property, CXString classUSR) { - StringUSRGenerator SUG; - SUG << extractUSRSuffix(clang_getCString(classUSR)); - SUG->GenObjCProperty(property); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCProperty(property); + return createCXString(UG.str(), true); } } // end extern "C" diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index d3de94a7a561..62c973852dc1 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(libclang CIndexUSRs.cpp CIndexer.cpp CXCursor.cpp + CXTypes.cpp ../../include/clang-c/Index.h ) set_target_properties(libclang PROPERTIES OUTPUT_NAME clang) diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index c8eb4823779b..f7192dd7e2c8 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -56,13 +56,14 @@ static CXCursorKind GetCursorKind(Decl *D) { case Decl::ParmVar: return CXCursor_ParmDecl; case Decl::Typedef: return CXCursor_TypedefDecl; case Decl::Var: return CXCursor_VarDecl; + case Decl::Namespace: return CXCursor_Namespace; default: if (TagDecl *TD = dyn_cast<TagDecl>(D)) { switch (TD->getTagKind()) { - case TagDecl::TK_struct: return CXCursor_StructDecl; - case TagDecl::TK_class: return CXCursor_ClassDecl; - case TagDecl::TK_union: return CXCursor_UnionDecl; - case TagDecl::TK_enum: return CXCursor_EnumDecl; + case TTK_Struct: return CXCursor_StructDecl; + case TTK_Class: return CXCursor_ClassDecl; + case TTK_Union: return CXCursor_UnionDecl; + case TTK_Enum: return CXCursor_EnumDecl; } } @@ -79,6 +80,7 @@ static CXCursorKind GetCursorKind(const Attr *A) { default: break; case Attr::IBActionKind: return CXCursor_IBActionAttr; case Attr::IBOutletKind: return CXCursor_IBOutletAttr; + case Attr::IBOutletCollectionKind: return CXCursor_IBOutletCollectionAttr; } return CXCursor_UnexposedAttr; diff --git a/tools/libclang/CXTypes.cpp b/tools/libclang/CXTypes.cpp new file mode 100644 index 000000000000..137370adb200 --- /dev/null +++ b/tools/libclang/CXTypes.cpp @@ -0,0 +1,249 @@ +//===- CXTypes.cpp - Implements 'CXTypes' aspect of libclang ------------===// +// +// 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 'CXTypes' API hooks in the Clang-C library. +// +//===--------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Frontend/ASTUnit.h" + +using namespace clang; + +static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) { +#define BTCASE(K) case BuiltinType::K: return CXType_##K + switch (BT->getKind()) { + BTCASE(Void); + BTCASE(Bool); + BTCASE(Char_U); + BTCASE(UChar); + BTCASE(Char16); + BTCASE(Char32); + BTCASE(UShort); + BTCASE(UInt); + BTCASE(ULong); + BTCASE(ULongLong); + BTCASE(UInt128); + BTCASE(Char_S); + BTCASE(SChar); + BTCASE(WChar); + BTCASE(Short); + BTCASE(Int); + BTCASE(Long); + BTCASE(LongLong); + BTCASE(Int128); + BTCASE(Float); + BTCASE(Double); + BTCASE(LongDouble); + BTCASE(NullPtr); + BTCASE(Overload); + BTCASE(Dependent); + BTCASE(ObjCId); + BTCASE(ObjCClass); + BTCASE(ObjCSel); + default: + return CXType_Unexposed; + } +#undef BTCASE +} + +static CXTypeKind GetTypeKind(QualType T) { + Type *TP = T.getTypePtr(); + if (!TP) + return CXType_Invalid; + +#define TKCASE(K) case Type::K: return CXType_##K + switch (TP->getTypeClass()) { + case Type::Builtin: + return GetBuiltinTypeKind(cast<BuiltinType>(TP)); + TKCASE(Complex); + TKCASE(Pointer); + TKCASE(BlockPointer); + TKCASE(LValueReference); + TKCASE(RValueReference); + TKCASE(Record); + TKCASE(Enum); + TKCASE(Typedef); + TKCASE(ObjCInterface); + TKCASE(ObjCObjectPointer); + default: + return CXType_Unexposed; + } +#undef TKCASE +} + +static CXType MakeCXType(QualType T, ASTUnit *TU) { + CXTypeKind TK = GetTypeKind(T); + CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }}; + return CT; +} + +static inline QualType GetQualType(CXType CT) { + return QualType::getFromOpaquePtr(CT.data[0]); +} + +static inline ASTUnit* GetASTU(CXType CT) { + return static_cast<ASTUnit*>(CT.data[1]); +} + +extern "C" { + +CXType clang_getCursorType(CXCursor C) { + ASTUnit *AU = cxcursor::getCursorASTUnit(C); + + if (clang_isExpression(C.kind)) { + QualType T = cxcursor::getCursorExpr(C)->getType(); + return MakeCXType(T, AU); + } + + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + + if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) + return MakeCXType(QualType(TD->getTypeForDecl(), 0), AU); + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return MakeCXType(QualType(ID->getTypeForDecl(), 0), AU); + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + return MakeCXType(VD->getType(), AU); + + return MakeCXType(QualType(), AU); + } + + return MakeCXType(QualType(), AU); +} + +CXType clang_getCanonicalType(CXType CT) { + if (CT.kind == CXType_Invalid) + return CT; + + QualType T = GetQualType(CT); + + if (T.isNull()) + return MakeCXType(QualType(), GetASTU(CT)); + + ASTUnit *AU = GetASTU(CT); + return MakeCXType(AU->getASTContext().getCanonicalType(T), AU); +} + +CXType clang_getPointeeType(CXType CT) { + QualType T = GetQualType(CT); + Type *TP = T.getTypePtr(); + + if (!TP) + return MakeCXType(QualType(), GetASTU(CT)); + + switch (TP->getTypeClass()) { + case Type::Pointer: + T = cast<PointerType>(TP)->getPointeeType(); + break; + case Type::BlockPointer: + T = cast<BlockPointerType>(TP)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + T = cast<ReferenceType>(TP)->getPointeeType(); + break; + case Type::ObjCObjectPointer: + T = cast<ObjCObjectPointerType>(TP)->getPointeeType(); + break; + default: + T = QualType(); + break; + } + return MakeCXType(T, GetASTU(CT)); +} + +CXCursor clang_getTypeDeclaration(CXType CT) { + QualType T = GetQualType(CT); + Type *TP = T.getTypePtr(); + Decl *D = 0; + + switch (TP->getTypeClass()) { + case Type::Typedef: + D = cast<TypedefType>(TP)->getDecl(); + break; + case Type::ObjCObject: + D = cast<ObjCObjectType>(TP)->getInterface(); + break; + case Type::ObjCInterface: + D = cast<ObjCInterfaceType>(TP)->getDecl(); + break; + case Type::Record: + case Type::Enum: + D = cast<TagType>(TP)->getDecl(); + break; + default: + break; + } + + if (!D) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + return cxcursor::MakeCXCursor(D, GetASTU(CT)); +} + +CXString clang_getTypeKindSpelling(enum CXTypeKind K) { + const char *s = 0; +#define TKIND(X) case CXType_##X: s = "" #X ""; break + switch (K) { + TKIND(Invalid); + TKIND(Unexposed); + TKIND(Void); + TKIND(Bool); + TKIND(Char_U); + TKIND(UChar); + TKIND(Char16); + TKIND(Char32); + TKIND(UShort); + TKIND(UInt); + TKIND(ULong); + TKIND(ULongLong); + TKIND(UInt128); + TKIND(Char_S); + TKIND(SChar); + TKIND(WChar); + TKIND(Short); + TKIND(Int); + TKIND(Long); + TKIND(LongLong); + TKIND(Int128); + TKIND(Float); + TKIND(Double); + TKIND(LongDouble); + TKIND(NullPtr); + TKIND(Overload); + TKIND(Dependent); + TKIND(ObjCId); + TKIND(ObjCClass); + TKIND(ObjCSel); + TKIND(Complex); + TKIND(Pointer); + TKIND(BlockPointer); + TKIND(LValueReference); + TKIND(RValueReference); + TKIND(Record); + TKIND(Enum); + TKIND(Typedef); + TKIND(ObjCInterface); + TKIND(ObjCObjectPointer); + } +#undef TKIND + return cxstring::createCXString(s); +} + +unsigned clang_equalTypes(CXType A, CXType B) { + return A.data[0] == B.data[0] && A.data[1] == B.data[1];; +} + +} // end: extern "C" diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile index a7877bf8e16b..ff0fa33e41eb 100644 --- a/tools/libclang/Makefile +++ b/tools/libclang/Makefile @@ -50,6 +50,6 @@ ifeq ($(HOST_OS),Darwin) ifneq ($(DARWIN_VERS),8) LLVMLibsOptions := $(LLVMLibsOptions) \ -no-undefined -Wl,-install_name \ - -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index b36116805311..a9f4f0777cdc 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -1,3 +1,4 @@ +_clang_CXXMethod_isStatic _clang_annotateTokens _clang_codeComplete _clang_codeCompleteGetDiagnostic @@ -21,12 +22,15 @@ _clang_disposeTranslationUnit _clang_enableStackTraces _clang_equalCursors _clang_equalLocations +_clang_equalTypes _clang_formatDiagnostic _clang_getCString +_clang_getCanonicalType _clang_getClangVersion _clang_getCompletionChunkCompletionString _clang_getCompletionChunkKind _clang_getCompletionChunkText +_clang_getCompletionPriority _clang_getCursor _clang_getCursorDefinition _clang_getCursorExtent @@ -37,6 +41,7 @@ _clang_getCursorLinkage _clang_getCursorLocation _clang_getCursorReferenced _clang_getCursorSpelling +_clang_getCursorType _clang_getCursorUSR _clang_getDefinitionSpellingAndExtent _clang_getDiagnostic @@ -58,6 +63,7 @@ _clang_getNullLocation _clang_getNullRange _clang_getNumCompletionChunks _clang_getNumDiagnostics +_clang_getPointeeType _clang_getRange _clang_getRangeEnd _clang_getRangeStart @@ -67,9 +73,12 @@ _clang_getTokenLocation _clang_getTokenSpelling _clang_getTranslationUnitCursor _clang_getTranslationUnitSpelling +_clang_getTypeDeclaration +_clang_getTypeKindSpelling _clang_isCursorDefinition _clang_isDeclaration _clang_isExpression +_clang_isFromMainFile _clang_isInvalid _clang_isPreprocessing _clang_isReference diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 991bb067f7d0..b09e6ac56c85 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -1,3 +1,4 @@ +clang_CXXMethod_isStatic clang_annotateTokens clang_codeComplete clang_codeCompleteGetDiagnostic @@ -21,12 +22,15 @@ clang_disposeTranslationUnit clang_enableStackTraces clang_equalCursors clang_equalLocations +clang_equalTypes clang_formatDiagnostic clang_getCString +clang_getCanonicalType clang_getClangVersion clang_getCompletionChunkCompletionString clang_getCompletionChunkKind clang_getCompletionChunkText +clang_getCompletionPriority clang_getCursor clang_getCursorDefinition clang_getCursorExtent @@ -37,6 +41,7 @@ clang_getCursorLinkage clang_getCursorLocation clang_getCursorReferenced clang_getCursorSpelling +clang_getCursorType clang_getCursorUSR clang_getDefinitionSpellingAndExtent clang_getDiagnostic @@ -58,6 +63,7 @@ clang_getNullLocation clang_getNullRange clang_getNumCompletionChunks clang_getNumDiagnostics +clang_getPointeeType clang_getRange clang_getRangeEnd clang_getRangeStart @@ -67,9 +73,12 @@ clang_getTokenLocation clang_getTokenSpelling clang_getTranslationUnitCursor clang_getTranslationUnitSpelling +clang_getTypeDeclaration +clang_getTypeKindSpelling clang_isCursorDefinition clang_isDeclaration clang_isExpression +clang_isFromMainFile clang_isInvalid clang_isPreprocessing clang_isReference @@ -79,3 +88,4 @@ clang_isUnexposed clang_setUseExternalASTGeneration clang_tokenize clang_visitChildren + diff --git a/www/analyzer/annotations.html b/www/analyzer/annotations.html index 620471346365..5184aeddfef4 100644 --- a/www/analyzer/annotations.html +++ b/www/analyzer/annotations.html @@ -53,7 +53,9 @@ recognized by GCC. Their use can be conditioned using preprocessor macros <li><a href="#cocoa_mem">Cocoa & Core Foundation Memory Management Annotations</a> <ul> <li><a href="#attr_ns_returns_retained">Attribute 'ns_returns_retained'</a></li> + <li><a href="#attr_ns_returns_not_retained">Attribute 'ns_returns_not_retained'</a></li> <li><a href="#attr_cf_returns_retained">Attribute 'cf_returns_retained'</a></li> + <li><a href="#attr_cf_returns_not_retained">Attribute 'cf_returns_not_retained'</a></li> </ul> </li> </ul> @@ -190,6 +192,36 @@ use 'cf_returns_retained'.</p> <img src="images/example_ns_returns_retained.png"> +<h4 id="attr_ns_returns_not_retained">Attribute 'ns_returns_not_retained' +(Clang-specific)</h4> + +<p>The 'ns_returns_not_retained' attribute is the complement of '<a +href="#attr_ns_returns_retained">ns_returns_retained</a>'. Where a function or +method may appear to obey the Cocoa conventions and return a retained Cocoa +object, this attribute can be used to indicate that the object reference +returned should not be considered as an "owning" reference being +returned to the caller.</p> + +<p>Usage is identical to <a +href="#attr_ns_returns_retained">ns_returns_retained</a>. When using the +attribute, be sure to declare it within the proper macro that checks for +its availability, as it is not available in earlier versions of the analyzer:</p> + +<pre class="code_example"> +<span class="command">$ cat test.m</span> +#ifndef __has_feature // Optional. +#define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef NS_RETURNS_NOT_RETAINED +#if __has_feature(attribute_ns_returns_not_retained) +<span class="code_highlight">#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))</span> +#else +#define NS_RETURNS_NOT_RETAINED +#endif +#endif +</pre> + <h4 id="attr_cf_returns_retained">Attribute 'cf_returns_retained' (Clang-specific)</h4> @@ -288,6 +320,36 @@ collection:</p> <img src="images/example_cf_returns_retained_gc.png"> +<h4 id="attr_cf_returns_not_retained">Attribute 'cf_returns_not_retained' +(Clang-specific)</h4> + +<p>The 'cf_returns_not_retained' attribute is the complement of '<a +href="#attr_cf_returns_retained">cf_returns_retained</a>'. Where a function or +method may appear to obey the Core Foundation or Cocoa conventions and return +a retained Core Foundation object, this attribute can be used to indicate that +the object reference returned should not be considered as an +"owning" reference being returned to the caller.</p> + +<p>Usage is identical to <a +href="#attr_cf_returns_retained">cf_returns_retained</a>. When using the +attribute, be sure to declare it within the proper macro that checks for +its availability, as it is not available in earlier versions of the analyzer:</p> + +<pre class="code_example"> +<span class="command">$ cat test.m</span> +#ifndef __has_feature // Optional. +#define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef CF_RETURNS_NOT_RETAINED +#if __has_feature(attribute_cf_returns_not_retained) +<span class="code_highlight">#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))</span> +#else +#define CF_RETURNS_NOT_RETAINED +#endif +#endif +</pre> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <h2 id="custom_assertions">Custom Assertion Handlers</h2> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl index 413130609217..ecc516a641f4 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-240.tar.bz2">checker-240.tar.bz2</a></b> (built April 11, 2010) +<b><a href="http://files.me.com/tkremenek/mt0ve6">checker-241.tar.bz2</a></b> (built May 26, 2010) diff --git a/www/clang-tutorial.html b/www/clang-tutorial.html new file mode 100644 index 000000000000..0e17046996e9 --- /dev/null +++ b/www/clang-tutorial.html @@ -0,0 +1,56 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> + <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> + <title>Clang - Quick Tutorial</title> + <link type="text/css" rel="stylesheet" href="menu.css" /> + <link type="text/css" rel="stylesheet" href="content.css" /> +</head> +<body> + +<!--#include virtual="menu.html.incl"--> + +<div id="content"> + +<h1>Tutorial</h1> + + <p>Invoking the BoostCon tool:</p> + <pre> +$ clang -cc1 -boostcon t.cpp +</pre> + + <p>Teach the BoostCon action to identify and print C++ classes:</p> + <pre> +bool VisitCXXRecordDecl(CXXRecordDecl *D) { + std::cout << D->getNameAsString() + << '\n'; + return false; +} +</pre> + + <p>Walk and print base classes of a class:</p> + <pre> +for(CXXRecordDecl::base_class_iterator + B = D->bases_begin(), BEnd = D->bases_end(); + B != BEnd; ++B) { + QualType BaseType = B->getType(); + std::cout << " " << BaseType.getAsString() + << '\n'; +} +</pre> + + <p>Retrieve the C++ class declaration from a base type:</p> + <pre> +if (const RecordType *RTy + = BaseType->getAs<RecordType>()) { + RecordDecl *Base = RTy->getDecl(); + if (CXXRecordDecl *BaseCXX + = dyn_cast<CXXRecordDecl>(Base)) { + + } +} +</pre> +</div> +</body> +</html> diff --git a/www/comparison.html b/www/comparison.html index 0a6a7c8e00fa..dcf6220eb95f 100644 --- a/www/comparison.html +++ b/www/comparison.html @@ -50,8 +50,10 @@ <ul> <li>GCC supports languages that clang does not aim to, such as Java, Ada, FORTRAN, etc.</li> - <li>GCC front-ends are very mature and already support C++. - <a href="cxx_status.html">clang's support for C++</a> is further behind.</li> + <li><a href="cxx_status.html">Clang support for C++</a> is more compliant + than GCC's in many ways, but is not as mature as GCC's. GCC has several + C++'0x features that Clang does not yet support (e.g. variadic + templates).</li> <li>GCC supports more targets than LLVM.</li> <li>GCC is popular and widely adopted.</li> <li>GCC does not require a C++ compiler to build it.</li> diff --git a/www/cxx_compatibility.html b/www/cxx_compatibility.html index bd48c6c09d38..fe032403d7c7 100644 --- a/www/cxx_compatibility.html +++ b/www/cxx_compatibility.html @@ -42,14 +42,25 @@ C++-conformance bug in your code and how you can fix it.</p> <h2 id="vla">Variable-length arrays</h2> <!-- ======================================================================= --> -<p>GCC allows an array's size to be determined at run time. This, -however, is not standard C++. Furthermore, it is a potential security -hole as an incorrect array size may overflow the stack. If Clang tells -you <tt>"variable length arrays are not permitted in C++"</tt>, here -are some ways in which you can fix it:</p> +<p>GCC and C99 allow an array's size to be determined at run +time. This extension is not permitted in standard C++. However, Clang +supports such variable length arrays in very limited circumstances for +compatibility with GNU C and C99 programs:</p> + +<ul> + <li>The element type of a variable length array must be a POD + ("plain old data") type, which means that it cannot have any + user-declared constructors or destructors, base classes, or any + members if non-POD type. All C types are POD types.</li> + + <li>Variable length arrays cannot be used as the type of a non-type +template parameter.</li> </ul> + +<p>If your code uses variable length arrays in a manner that Clang doesn't support, there are several ways to fix your code: <ol> -<li>replace it with a fixed-size array if you can determine a +<li>replace the variable length array with a fixed-size array if you can + determine a reasonable upper bound at compile time; sometimes this is as simple as changing <tt>int size = ...;</tt> to <tt>const int size = ...;</tt> (if the definition of <tt>size</tt> is a compile-time diff --git a/www/cxx_status.html b/www/cxx_status.html index 9ba3200faba8..8fccc2a34137 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -3,7 +3,7 @@ <html> <head> <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> - <title>Clang - C++ Support</title> + <title>Clang - C++ and C++'0x Status</title> <link type="text/css" rel="stylesheet" href="menu.css"> <link type="text/css" rel="stylesheet" href="content.css"> <style type="text/css"> @@ -22,11 +22,9 @@ <div id="content"> <!--*************************************************************************--> -<h1>C++ Support in Clang</h1> +<h1>C++ and C++'0x Support in Clang</h1> <!--*************************************************************************--> -<p>Last updated: $Date: 2010-04-12 18:01:38 +0200 (Mon, 12 Apr 2010) $</p> - -<h1>Clang C++ Status</h1> +<p>Last updated: $Date: 2010-05-21 23:16:21 +0200 (Fri, 21 May 2010) $</p> <ul> <li><a href="#projects">Projects Building with Clang</a></li> @@ -34,19 +32,19 @@ <li><a href="#cxx0x">C++0x Status</a></li> </ul> -<p>Clang currently implements nearly all of the ISO C++ 1998 standard (including the defects addressed in the ISO C++ 2003 standard). However, the implementation of Clang C++ is still quite immature, with many remaining bugs that are likely to cause compiler crashes, erroneous errors and warnings, and miscompiled code. The <a href="http://llvm.org/bugs/">LLVM bug tracker</a> contains a Clang C++ component that tracks known Clang C++ bugs.</p> +<p>Clang currently implements all of the ISO C++ 1998 standard (including + the defects addressed in the ISO C++ 2003 standard) except for 'export' + (which has been removed from the C++'0x draft). + However, the implementation of Clang C++ is still somewhat immature, with + remaining bugs that may cause compiler crashes, erroneous errors and warnings, + or miscompiled code. The <a href="http://llvm.org/bugs/">LLVM bug tracker</a> + contains a Clang C++ component that tracks known Clang C++ bugs.</p> <h2 id="projects">Projects Building with Clang</h2> - <p>Clang is now capable of compiling some language C++ projects, or -large pieces of such projects. The following table describes various -projects that we have attempted to compile with Clang along with the results of that attempt.</p> - - <p> At this point in time, each new C++ project typically uncovers -new bugs. We keep track of these in the <a - href="http://llvm.org/bugs/">LLVM bug tracker</a> via tracking bugs, -which are used to relate all of the bugs known to affect that -particular project. Introducing a new project in this list typically requires a liason familiar with LLVM or Clang development, who is able to provide detailed bug reports and track progress for the particular project.</p> + <p>Clang is now capable of compiling large C++ projects, and the following + table describes various projects that we have attempted to compile with + Clang++.</p> <table width="689" border="1" cellspacing="0"> <tr> @@ -68,20 +66,28 @@ particular project. Introducing a new project in this list typically requires a <td></td> </tr> <tr> + <td><a href="http://www.boost.org">Boost</a></td> + <td><a href="http://blog.llvm.org/2010/05/clang-builds-boost.html">Compiles + and passes regression tests</a> on Darwin/X86-64.</td> + <td>May 20, 2010</td> + <td><a href="http://llvm.org/bugs/show_bug.cgi?id=6023">PR6023</a></td> + </tr> + <tr> <td><a href="http://qt.nokia.com">Qt</a></td> <td>Partially compiles; miscompilation of uic prevents complete compilation, qmake works, some small examples also.</td> <td>February 9, 2010</td> <td><a href="http://llvm.org/bugs/show_bug.cgi?id=5881">PR5881</a></td> </tr> - <tr> - <td><a href="http://www.boost.org">Boost</a></td> - <td>Some libraries (e.g., Boost.MPL) successfully build and pass regression tests, the majority still fail.</td> - <td>February 5, 2010</td> - <td><a href="http://llvm.org/bugs/show_bug.cgi?id=6023">PR6023</a></td> - </tr> </table> - <h2 id="specification">Implementation Status by Section</h2> +<h2 id="cxx0x">C++0x Implementation status</h2> + +<p>Clang's development effort is focused primarily on fixing bugs in the current +ISO C++ standard (1998/2003). This section tracks the status of various C++0x +features.</p> + + +<h2 id="specification">Implementation Status by Feature</h2> <!-- Within this table: The colors we're using to color-code our level @@ -96,9 +102,9 @@ of support for a given section: --> <p>The following table is used to help track our implementation - progress toward implementing the complete C++03 standard. We use a + progress toward implementing the complete C++'0x standard. We use a simple, somewhat arbitrary color-coding scheme to describe the - relative completeness of features by section:</p> + relative completeness of features:</p> <table width="689" border="1" cellspacing="0"> <tr> @@ -125,2239 +131,46 @@ of support for a given section: <p>A feature is "complete" when the appropriate Clang component (Parse, AST, Sema, CodeGen) implements the behavior described in all of the -paragraphs in the relevant C++ standard. Note that many C++ features are -actually described in several different sections within the standard. The major components are:</p> +paragraphs in the relevant C++'0x draft standard. The major +components are:</p> <dl> <dt>Parse</dt> - <dd>Clang is able to parse the grammar of this feature (or the grammar described by this section), but does not necessarily do anything with the parsed result. Use Clang's <code>-fsyntax-only</code> option to parse C++ programs.</dd> + <dd>Clang is able to parse the grammar of this feature (or the grammar + described by this section), but does not necessarily do anything with the + parsed result. Use Clang's <code>-fsyntax-only</code> option to parse C++ + programs.</dd> <dt>AST</dt> - <dd>Clang builds an abstract syntax tree (AST) for the feature, but does not necessarily perform any type-checking. Use Clang's <code>-ast-print</code> option to print the resulting ASTs.</dd> + <dd>Clang builds an abstract syntax tree (AST) for the feature, but does not + necessarily perform any type-checking. Use Clang's <code>-ast-print</code> + option to print the resulting ASTs.</dd> <dt>Sema</dt> - <dd>Clang parses and type-checks this feature and provides a well-formed AST annotated with types. Use Clang's <code>-fsyntax-only</code> to type-check code.</dd> + <dd>Clang parses and type-checks this feature and provides a well-formed AST + annotated with types. Use Clang's <code>-fsyntax-only</code> to type-check + code.</dd> <dt>CodeGen</dt> - <dd>Clang parses, type-checks, and generates code for this feature, allowing one to compile and execute programs.</dd> + <dd>Clang parses, type-checks, and generates code for this feature, allowing + one to compile and execute programs.</dd> </dl> -<p>Updates to this table are welcome! Since Clang already supports -much of C, and therefore much C++, many of the currently-white cells -could be filled in. If you wish to do so, please compare Clang's -implementation against the C++ standard and provide a patch that -updates the table accordingly. Tests for the various features are also +<p>Updates to this table are welcome! Tests for the various features are also welcome!</p> <table width="689" border="1" cellspacing="0"> +<tr><td colspan="6" align="center" bgcolor="#ffffcc">C++0x Features</td> +</tr> <tr> - <th>Section</th> + <th>Feature</th> <th>Parse</th> <th>AST</th> <th>Sema</th> <th>CodeGen</th> <th>Notes</th> </tr> -<tr> - <td>2 [lex]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.1 [lex.phases]</td> - <td class="advanced" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td>Extended characters aren't handled.</td> -</tr> -<tr> - <td> 2.2 [lex.charset]</td> - <td class="basic"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td>No support for extended characters.</td> -</tr> -<tr> - <td> 2.3 [lex.trigraph]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.4 [lex.pptoken]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.5 [lex.digraph]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.6 [lex.token]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.7 [lex.comment]</td> - <td class="advanced" align="center"></td> - <td></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td>NDR "form feed or vtab in comment" is not diagnosed.</td> -</tr> -<tr> - <td> 2.8 [lex.header]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.9 [lex.ppnumber]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.10 [lex.name]</td> - <td class="advanced" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td>No support for extended characters</td> -</tr> -<tr> - <td> 2.11 [lex.key]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.12 [lex.operators]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.13 [lex.literal]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.13.1 [lex.icon]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.13.2 [lex.ccon]</td> - <td class="advanced" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td>Poor support for extended characters</td> -</tr> -<tr> - <td> 2.13.3 [lex.fcon]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 2.13.4 [lex.string]</td> - <td class="advanced" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td>Poor support for extended characters</td> -</tr> -<tr> - <td> 2.13.5 [lex.bool]</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> -<td>3 [basic]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.1 [basic.def]</td> - <td></td> - <td></td> - <td></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.2 [basic.def.odr]</td> - <td></td> - <td></td> - <td></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 3.3 [basic.scope]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.3.1 [basic.scope.pdecl]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.3.2 [basic.scope.local]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.3.3 [basic.scope.proto]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.3.4 [basic.funscope]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.3.5 [basic.scope.namespace]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.3.6 [basic.scope.class]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="advanced"></td> - <td class="na">N/A</td> - <td>Does not check that reordering the members of a class maintains semantics.</td> -</tr> -<tr> - <td> 3.3.7 [basic.scope.hiding]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.4 [basic.lookup]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.4.1 [basic.lookup.unqual]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="advanced"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.4.2 [basic.lookup.argdep]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.4.3 [basic.lookup.qual]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="advanced"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.4.3.1 [class.qual]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="advanced"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 3.4.3.2 [namespace.qual]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="advanced"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr><td> 3.4.4 [basic.lookup.elab]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr> - <td> 3.4.5 [basic.lookup.classref]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="advanced"></td> - <td class="na">N/A</td> - <td>Missing ambiguity/consistency checks for paragraphs 3 (~type-name) and 7 (conversion-type-id)</td> -</tr> -<tr> - <td> 3.4.6 [basic.lookup.udir]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="medium"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr><td> 3.5 [basic.link]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.6 [basic.start]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.6.1 [basic.start.main]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.6.2 [basic.start.init]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.6.3 [basic.start.term]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.7 [basic.stc]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.7.1 [basic.stc.static]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.7.2 [basic.stc.auto]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.7.3 [basic.stc.dynamic]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.7.3.1 [basic.stc.dynamic.allocation]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.7.3.2 [basic.stc.dynamic.deallocation]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.7.4 [basic.stc.inherit]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.8 [basic.life]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.9 [basic.types]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.9.1 [basic.fundamental]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.9.2 [basic.compound]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.9.3 [basic.type.qualifier]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 3.10 [basic.lval]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr> - <td>4 [conv]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.1 [conv.lval]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> <!-- p2: sizeof --> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.2 [conv.array]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.3 [conv.func]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.4 [conv.qual]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.5 [conv.prom]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.6 [conv.fpprom]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.7 [conv.integral]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.8 [conv.double]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.9 [conv.fpint]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.10 [conv.ptr]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.11 [conv.mem]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 4.12 [conv.bool]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td>5 [expr]</td> - <td class="na">N/A</td> - <td class="na">N/A</td> - <td class="complete" align="center">✓</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 5.1 [expr.prim]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td></td> -</tr> -<tr><td> 5.2 [expr.post]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr> - <td> 5.2.1 [expr.sub]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.2.2 [expr.call]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.2.3 [expr.type.conv]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.2.4 [expr.pseudo]</td> - <td class="complete"></td> - <td class="complete"></td> - <td class="complete"></td> - <td class="complete"></td> - <td></td> -</tr> -<tr> - <td> 5.2.5 [expr.ref]</td> - <td class="complete" align="center"></td> - <td class="complete"></td> - <td class="complete"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.2.6 [expr.post.incr]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.2.7 [expr.dynamic.cast]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.2.8 [expr.typeid]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.2.9 [expr.static.cast]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.2.10 [expr.reinterpret.cast]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.2.11 [expr.const.cast]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr><td> 5.3 [expr.unary]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 5.3.1 [expr.unary.op]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr> - <td> 5.3.1p1 Unary *</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.3.1p2-5 Unary &</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.3.1p6 Unary +</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.3.1p7 Unary -</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.3.1p8 Unary !</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.3.1p9 Unary ~</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.3.2 [expr.pre.incr]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.3.3 [expr.sizeof]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.3.4 [expr.new]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td>operator delete is not looked up, initialization not quite correct</td> -</tr> -<tr> - <td> 5.3.5 [expr.delete]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.4 [expr.cast]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.5 [expr.mptr.oper]</td> - <td class="complete" align="center"></td> - <td class="advanced"></td> - <td class="advanced"></td> - <td></td> - <td>Dereferenced member function pointers have the wrong type(see FIXME in CheckPointerToMemberOperands).</td> -</tr> -<tr> - <td> 5.6 [expr.mul]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.7 [expr.add]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.8 [expr.shift]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.9 [expr.rel]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.10 [expr.eq]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.11 [expr.bit.and]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.12 [expr.xor]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.13 [expr.or]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.14 [expr.log.and]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.15 [expr.log.or]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.16 [expr.cond]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td>some invalid hierarchy casts still accepted, but that's a general problem</td> -</tr> -<tr> - <td> 5.17 [expr.ass]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.18 [expr.comma]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 5.19 [expr.const]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="basic"></td> - <td></td> - <td>Uses C semantics</td> -</tr> -<tr> - <td>6 [stmt.stmt]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.1 [stmt.label]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.2 [stmt.expr]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.3 [stmt.block]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.4 [stmt.select]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td>Conversion of declarations to required types not really supported.</td> -</tr> -<tr> - <td> 6.4.1 [stmt.if]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.4.2 [stmt.switch]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.5 [stmt.iter]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td>Conversion of declarations to required types not really supported.</td> -</tr> -<tr> - <td> 6.5.1 [stmt.while]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.5.2 [stmt.do]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.5.3 [stmt.for]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.6 [stmt.jump]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.6.1 [stmt.break]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.6.2 [stmt.cont]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.6.3 [stmt.return]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.6.4 [stmt.goto]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 6.7 [stmt.dcl]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td>Existence and accessibility of destructors is not tested for.</td> -</tr> -<tr> - <td> 6.8 [stmt.ambig]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr><td>7 [dcl.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> - 7.1 [dcl.spec]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.1.1 [dcl.stc]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> - <td>Linkage merging has some errors.</td> -</tr> -<tr> - <td> 7.1.2 [dcl.fct.spec]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.1.3 [dcl.typedef]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> -</tr> -<tr> - <td> 7.1.4 [dcl.friend]</td> - <td class="medium"></td> - <td class="medium"></td> - <td class="medium"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.1.5 [dcl.type]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.1.5.1 [dcl.type.cv]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.1.5.2 [dcl.type.simple]</td> - <td class="advanced"></td> - <td class="advanced"></td> - <td class="advanced"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.1.5.3 [dcl.type.elab]</td> - <td class="advanced"></td> - <td class="advanced"></td> - <td class="advanced"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.2 [dcl.enum]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.3 [basic.namespace]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.3.1 [namespace.def]</td> - <td class="advanced"></td> - <td class="advanced"></td> - <td class="advanced"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.3.1.1 [namespace.unnamed]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.3.1.2 [namespace.memdef]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.3.2 [namespace.alias]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 7.3.3 [namespace.udecl]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 7.3.4[namespace.udir]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced"></td> - <td class="broken" align="center"></td> - <td>Example in p4 fails.</td> -</tr> -<tr><td> - 7.4 [dcl.asm]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 7.5 [dcl.link]</td> - <td class="complete" align="center"></td> - <td class="medium"></td> - <td class="medium"></td> - <td></td> - <td></td> -</tr> -<tr> - <td>8 [dcl.decl]</td><td></td><td></td><td></td><td></td><td></td> -</tr> -<tr> - <td> 8.1 [dcl.name]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 8.2 [dcl.ambig.res]</td> - <td class="complete" align="center">✓</td> - <td class="na" align="center">N/A</td> - <td class="complete" align="center">✓</td> - <td class="na">N/A</td> - <td></td> -</tr> -<tr> - <td> 8.3 [dcl.meaning]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na">N/A</td> - <td></td> -</tr> - <tr> - <td> 8.3.1 [dcl.ptr]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> - </tr> - <tr> - <td> 8.3.2 [dcl.ref]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> - </tr> - <tr> - <td> 8.3.3 [dcl.mptr]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> - </tr> - <tr> - <td> 8.3.4 [dcl.array]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> - </tr> - <tr> - <td> 8.3.5 [dcl.fct]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na">N/A</td> - <td></td> - </tr> - <tr> - <td> 8.3.6 [dcl.fct.default]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na">N/A</td> - <td>Partial support for default arguments of templates.</td> -</tr> -<tr> - <td> 8.4 [dcl.fct.def]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 8.5 [dcl.init]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 8.5.1[dcl.init.aggr]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td class="basic" align="center"></td> - <td>No CodeGen for dynamic initialization.</td> -</tr> -<tr> - <td> 8.5.2[dcl.init.string]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td class="basic" align="center"></td> - <td></td> -</tr> -<tr> - <td> 8.5.3 [dcl.init.ref]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td class="basic" align="center"></td> - <td></td> -</tr> -<tr> - <td>9 [class]</td> - <td class="advanced" align="center"></td> - <td></td> - <td></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 9.1 [class.name]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 9.2 [class.mem]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 9.3 [class.mfct]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="basic" align="center"></td> - <td></td> -</tr> -<tr> - <td> 9.3.1 [class.mfct.non-static]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="basic" align="center"></td> - <td></td> -</tr> -<tr> - <td> 9.3.2 [class.this]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="basic"></td> - <td></td> -</tr> -<tr> - <td> 9.4 [class.static]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="basic"></td> - <td></td> -</tr> -<tr> - <td> 9.4.1 [class.static.mfct]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="basic"></td> - <td></td> -</tr> -<tr> - <td> 9.4.2 [class.static.data]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="basic"></td> - <td></td> -</tr> -<tr> - <td> 9.5 [class.union]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete"></td> - <td class="complete"></td> - <td></td> -</tr> -<tr> - <td> 9.6 [class.bit]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> -</tr> -<tr> - <td> 9.7 [class.nest]</td> - <td class="complete" align="center"></td> - <td class="advanced"></td> - <td class="advanced"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 9.8 [class.local]</td> - <td class="complete" align="center">✓</td> - <td class="complete" align="center">✓</td> - <td class="complete" align="center">✓</td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 9.9 [class.nested.type]</td> - <td class="complete" align="center">✓</td> - <td class="complete" align="center">✓</td> - <td class="complete" align="center">✓</td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td>10 [class.derived]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 10.1 [class.mi]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 10.2 [class.member.lookup]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 10.3 [class.virtual]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 10.4 [class.abstract]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> - </tr> -<tr> - <td>11 [class.access]</td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td class="broken" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 11.1 [class.access.spec]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="complete" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 11.2 [class.access.base]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="broken" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 11.3 [class.access.dcl]</td> - <td class="broken" align="center"></td> - <td class="broken" align="center"></td> - <td class="broken" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 11.4 [class.friend]</td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 11.5 [class.protected]</td> - <td class="na" align="center"></td> - <td class="complete" align="center"></td> - <td class="broken" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 11.6 [class.access.virt]</td> - <td class="na" align="center"></td> - <td class="na" align="center"></td> - <td class="broken" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 11.7 [class.paths]</td> - <td class="na" align="center"></td> - <td class="na" align="center"></td> - <td class="broken" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 11.8 [class.access.nest]</td> - <td class="na" align="center"></td> - <td class="na" align="center"></td> - <td class="broken" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr><td>12 [special]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr> - <td> 12.1 [class.ctor]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> -</tr> -<tr> - <td> 12.2 [class.temporary]</td> - <td class="na" align="center">N/A</td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 12.3 [class.conv]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> -</tr> -<tr> - <td> 12.3.1 [class.conv.ctor]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> -</tr> -<tr> - <td> 12.3.2 [class.conv.fct]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> -</tr> -<tr> - <td> 12.4 [class.dtor]</td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr><td> 12.5 [class.free]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 12.6 [class.init]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 12.6.1 [class.expl.init]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr> - <td> 12.6.2 [class.base.init]</td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td>Most of the semantics of base initializations are implemented.</td> -</tr> -<tr><td> 12.7 [class.cdtor]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr> - <td> 12.8 [class.copy]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td>Most of the semantics of copy constructors are implemented.</td> -</tr> - -<tr><td>13 [over]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr> - <td> 13.1 [over.load]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 13.2 [over.dcl]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3 [over.match]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.1 [over.match.funcs]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.1.1 [over.match.call]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.1.1.1 [over.call.func]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.1.1.2 [over.call.object]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.1.2 [over.match.oper]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.1.3 [over.match.ctor]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.1.4 [over.match.copy]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.1.5 [over.match.conv]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.1.6 [over.match.ref]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.2 [over.match.viable]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.3 [over.match.best]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.3.1 [over.best.ics]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.3.1.1 [over.ics.scs]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.3.1.2 [over.ics.user]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.3.1.3 [over.ics.ellipsis]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.3.1.4 [over.ics.ref]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.3.3.2 [over.ics.rank]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.4 [over.over]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.5 [over.oper]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.5.1 [over.unary]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.5.2 [over.binary]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.5.3 [over.ass]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.5.4 [over.call]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.5.5 [over.sub]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.5.6 [over.ref]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.5.7 [over.inc]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 13.6 [over.built]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td class="na" align="center">N/A</td> - <td>Missing support for the ternary operator (p24, p25).</td> -</tr> -<tr> - <td>14 [temp]</td> - <td class="medium" align="center"></td> - <td class="basic" align="center"></td> - <td class="basic" align="center"></td> - <td class="broken" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.1 [temp.param]</td> - <td class="complete" align="center">✓</td> - <td class="complete" align="center">✓</td> - <td class="medium" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.2 [temp.names]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.3 [temp.arg]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.3.1 [temp.arg.type]</td> - <td class="complete" align="center">✓</td> - <td class="complete" align="center">✓</td> - <td class="complete" align="center"></td> - <td class="na" align="center">N/A</td> - <td>Paragraph 3 will be tested elsewhere</td> -</tr> -<tr> - <td> 14.3.2 [temp.arg.nontype]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.3.3 [temp.arg.template]</td> - <td class="complete" align="center"></td> - <td class="medium" align="center"></td> - <td class="basic" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.4 [temp.type]</td> - <td class="na" align="center">N/A</td> - <td class="complete" align="center">✓</td> - <td class="complete" align="center">✓</td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.5 [temp.decls]</td><td></td><td></td><td></td><td></td><td></td> -</tr> -<tr> - <td> 14.5.1 [temp.class]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.5.1.1 [temp.mem.func]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.5.1.2 [temp.mem.class]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.5.1.3 [temp.static]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.5.2 [temp.mem]</td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.5.3 [temp.friend]</td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td class="broken" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.5.4 [temp.class.spec]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.5.4.1 [temp.class.spec.match]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="complete" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.5.4.2 [temp.class.order]</td> - <td class="na" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.5.5.3 [temp.class.spec.mfunc]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.5.5 [temp.fct]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.5.5.1 [temp.over.link]</td> - <td class="na" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.5.5.2 [temp.func.order]</td> - <td class="na" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.6 [temp.res]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.1 [temp.local]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.2 [temp.dep]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.2.1 [temp.dep.type]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.2.2 [temp.dep.expr]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.2.3 [temp.dep.constexpr]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.2.4 [temp.dep.temp]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.3 [temp.nondep]</td> - <td class="na" align="center">N/A</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.4 [temp.dep.res]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.4.1 [temp.point]</td> - <td class="na" align="center">N/A</td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.6.4.2 [temp.dep.candidate]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td>Not restricted to functions with external linkage</td> -</tr> -<tr> - <td> 14.6.5 [temp.inject]</td> - <td class="na" align="center">N/A</td> - <td class="basic" align="center"></td> - <td class="basic" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.7 [temp.spec]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.7.1 [temp.inst]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.7.2 [temp.explicit]</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="complete" align="center"></td> - <td>Cannot test paragraph 11 until access control is implemented.<br/> - ASTs do not carry enough information to reproduce source code accurately.</td> -</tr> -<tr> - <td> 14.7.3 [temp.expl.spec]</td> - <td class="complete" align="center">✓</td> - <td class="advanced" align="center"></td> - <td class="complete" align="center">✓</td> - <td class="complete" align="center"></td> - <td>ASTs do not carry enough information to reproduce source code accurately</td> -</tr> -<tr> - <td> 14.8 [temp.fct.spec]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.8.1 [temp.arg.explicit]</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.8.2 [temp.deduct]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.8.2.1 [temp.deduct.call]</td> - <td class="na" align="center"></td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.8.2.2 [temp.deduct.funcaddr]</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.8.2.3 [temp.deduct.conv]</td> - <td class="na" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td> 14.8.2.4 [temp.deduct.type]</td> - <td class="na" align="center">N/A</td> - <td class="complete" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 14.8.3 [temp.over]</td> - <td class="na" align="center"></td> - <td class="advanced" align="center"></td> - <td class="advanced" align="center"></td> - <td class="na" align="center"></td> - <td></td> -</tr> -<tr> - <td>15 [except]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 15.1 [except.throw]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td></td> - <td></td> -</tr> -<tr> - <td> 15.2 [except.ctor]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td></td> - <td></td> -</tr> -<tr> - <td> 15.3 [except.handle]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="advanced" align="center"></td> - <td></td> - <td>Not all constraints are checked</td> -</tr> -<tr> - <td> 15.4 [except.spec]</td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="complete" align="center"></td> - <td class="broken"></td> - <td></td> -</tr> -<tr> - <td> 15.5 [except.special]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 15.5.1 [except.terminate]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 15.5.2 [except.unexpected]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 15.5.3 [except.uncaught]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td></td> -</tr> -<tr> - <td> 15.6 [except.access]</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td class="na" align="center">N/A</td> - <td>Redundant - struck from C++0x</td> -</tr> -<tr><td>16 [cpp]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.1 [cpp.cond]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.2 [cpp.include]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.3 [cpp.replace]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.3.1 [cpp.subst]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.3.2 [cpp.stringize]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.3.3 [cpp.concat]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.3.4 [cpp.rescan]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.3.5 [cpp.scope]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.4 [cpp.line]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.5 [cpp.error]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.6 [cpp.pragma]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.7 [cpp.null]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> 16.8 [cpp.predefined]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td>A [gram]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.1 [gram.key]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.2 [gram.lex]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.3 [gram.basic]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.4 [gram.expr]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.5 [gram.stmt]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.6 [gram.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.7 [gram.decl]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.8 [gram.class]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.9 [gram.derived]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.10 [gram.special]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.11 [gram.over]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.12 [gram.temp]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.13 [gram.except]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> A.14 [gram.cpp]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td>B [implimits]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td>C [diff]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1 [diff.iso]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1.1 [diff.lex]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1.2 [diff.basic]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1.3 [diff.expr]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1.4 [diff.stat]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1.5 [diff.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1.6 [diff.decl]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1.7 [diff.class]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1.8 [diff.special]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.1.9 [diff.cpp]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2 [diff.library]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2.1 [diff.mods.to.headers]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2.2 [diff.mods.to.definitions]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2.2.2 [diff.wchar.t]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2.2.3 [diff.header.iso646.h]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2.2.4 [diff.null]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2.3 [diff.mods.to.declarations]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2.4 [diff.mods.to.behavior]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2.4.1 [diff.offsetof]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> C.2.4.2 [diff.malloc]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td>D [depr]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> D.1 [depr.incr.bool]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> D.2 [depr.static]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> D.3 [depr.access.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> D.4 [depr.string]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td> D.5 [depr.c.headers]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr><td>E [extendid]</td><td></td><td></td><td></td><td></td><td></td></tr> -<tr> -</table> - <h2 id="cxx0x">C++0x Implementation status</h2> -<p>Clang's development effort is focused primarily on supporting the current ISO C++ standard (1998/2003). This section tracks the status of various C++0x features. In general, the implementations of these features are far less developed than C++98/03 features.</p> - -<table width="689" border="1" cellspacing="0"> - <td colspan="6" align="center" bgcolor="#ffffcc">C++0x Features</td> -</tr> <tr> <td>Explicit conversion operators (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">N2437</a>)</td> <td class="complete" align="center"></td> diff --git a/www/get_started.html b/www/get_started.html index 141698f6e812..96979af32d06 100644 --- a/www/get_started.html +++ b/www/get_started.html @@ -61,6 +61,11 @@ follows:</p> <li>Note: For subsequent Clang development, you can just do make at the clang directory level.</li> </ul> + + <p>It is also possible to use CMake instead of the makefiles. With CMake it + is also possible to generate project files for several IDEs: Eclipse CDT4, + CodeBlocks, Qt-Creator (use the CodeBlocks generator), KDevelop3.</p> + <li>If you intend to work on Clang C++ support, you may need to tell it how to find your C++ standard library headers. If Clang cannot find your system libstdc++ headers, please follow these instructions:</li> |